update
This commit is contained in:
467
.obsidian/plugins/math-in-callout/main.js
vendored
Normal file
467
.obsidian/plugins/math-in-callout/main.js
vendored
Normal file
@@ -0,0 +1,467 @@
|
||||
/*
|
||||
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __copyProps = (to, from, except, desc) => {
|
||||
if (from && typeof from === "object" || typeof from === "function") {
|
||||
for (let key of __getOwnPropNames(from))
|
||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
||||
}
|
||||
return to;
|
||||
};
|
||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
||||
|
||||
// src/main.ts
|
||||
var main_exports = {};
|
||||
__export(main_exports, {
|
||||
default: () => MathInCalloutPlugin
|
||||
});
|
||||
module.exports = __toCommonJS(main_exports);
|
||||
var import_obsidian3 = require("obsidian");
|
||||
|
||||
// src/decorations.ts
|
||||
var import_state2 = require("@codemirror/state");
|
||||
var import_language2 = require("@codemirror/language");
|
||||
var import_view = require("@codemirror/view");
|
||||
var import_obsidian = require("obsidian");
|
||||
|
||||
// src/quote-field.ts
|
||||
var import_language = require("@codemirror/language");
|
||||
var import_state = require("@codemirror/state");
|
||||
var QuoteInfo = class extends import_state.RangeValue {
|
||||
/**
|
||||
* @param level The level of the blockquote/callout (i.e. the number of ">"s).
|
||||
* @param isBaseCallout True if this is a callout or this is nested inside a callout of level 1.
|
||||
*/
|
||||
constructor(level, isBaseCallout) {
|
||||
super();
|
||||
this.level = level;
|
||||
this.isBaseCallout = isBaseCallout;
|
||||
this.pattern = this.level > 0 ? new RegExp(`^( {0,3}>){${this.level}}`) : null;
|
||||
}
|
||||
eq(other) {
|
||||
return this.level === other.level && this.isBaseCallout === other.isBaseCallout;
|
||||
}
|
||||
/** Remove ">"s that is misrecognized as inequality signs. */
|
||||
correctMath(math) {
|
||||
if (!this.pattern)
|
||||
return math;
|
||||
const lines = math.split("\n");
|
||||
return lines.map((line) => {
|
||||
const match = line.match(this.pattern);
|
||||
return match ? line.slice(match[0].length) : line;
|
||||
}).join("\n");
|
||||
}
|
||||
getBlockquoteBorderPositions(state, from, to) {
|
||||
const positions = [];
|
||||
const lineBegin = state.doc.lineAt(from);
|
||||
const lineEnd = state.doc.lineAt(to);
|
||||
for (let i = lineBegin.number; i <= lineEnd.number; i++) {
|
||||
const line = state.doc.line(i);
|
||||
let start = 0;
|
||||
for (let i2 = 0; i2 < this.level; i2++) {
|
||||
const index = line.text.indexOf(">", start);
|
||||
if (index === -1)
|
||||
continue;
|
||||
positions.push({ pos: index + line.from, first: i2 === 0 });
|
||||
start = index + 1;
|
||||
}
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
};
|
||||
var quoteInfoField = import_state.StateField.define({
|
||||
create(state) {
|
||||
return parseBlockquotes(state);
|
||||
},
|
||||
update(prev, tr) {
|
||||
return tr.docChanged ? parseBlockquotes(tr.state) : prev;
|
||||
}
|
||||
});
|
||||
function parseBlockquotes(state) {
|
||||
const tree = (0, import_language.syntaxTree)(state);
|
||||
const builder = new import_state.RangeSetBuilder();
|
||||
let level = 0;
|
||||
let from = -1;
|
||||
let isBaseCallout = false;
|
||||
for (let i = 1; i <= state.doc.lines; i++) {
|
||||
const line = state.doc.line(i);
|
||||
const match = line.text.match(/^( {0,3}>)+/);
|
||||
const newLevel = match ? match[0].split(">").length - 1 : 0;
|
||||
if (newLevel !== level) {
|
||||
if (level === 0 && newLevel === 1) {
|
||||
isBaseCallout = tree.cursorAt(line.from, 1).node.name.contains("-callout");
|
||||
}
|
||||
if (level > 0 && from >= 0) {
|
||||
builder.add(from, line.from, new QuoteInfo(level, isBaseCallout));
|
||||
}
|
||||
level = newLevel;
|
||||
from = line.from;
|
||||
}
|
||||
}
|
||||
if (level > 0 && from >= 0) {
|
||||
builder.add(from, state.doc.length, new QuoteInfo(level, isBaseCallout));
|
||||
}
|
||||
return builder.finish();
|
||||
}
|
||||
|
||||
// src/utils.ts
|
||||
function getQuoteInfo(state, pos) {
|
||||
const field = state.field(quoteInfoField, false);
|
||||
if (!field)
|
||||
return null;
|
||||
const { from, to, value } = field.iter(pos);
|
||||
if (from <= pos && pos <= to)
|
||||
return value;
|
||||
return null;
|
||||
}
|
||||
function hasOverlap(range, start, to) {
|
||||
return range.from <= to && range.to >= start;
|
||||
}
|
||||
function rangesHaveOverlap(ranges, start, to) {
|
||||
for (const range of ranges) {
|
||||
if (hasOverlap(range, start, to))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// src/decorations.ts
|
||||
var createCalloutDecorator = (BuiltInMathWidget) => import_state2.StateField.define({
|
||||
create() {
|
||||
return import_view.Decoration.none;
|
||||
},
|
||||
update(prev, tr) {
|
||||
const { state } = tr;
|
||||
const view = state.field(import_obsidian.editorEditorField);
|
||||
if (view.composing)
|
||||
return prev.map(tr.changes);
|
||||
const isSourceMode = !state.field(import_obsidian.editorLivePreviewField);
|
||||
const doc = state.doc;
|
||||
const ranges = view.hasFocus ? state.selection.ranges : [];
|
||||
const tree = (0, import_language2.syntaxTree)(state);
|
||||
const decorations = [];
|
||||
const makeDeco = (decorationSpec, from, to) => {
|
||||
if (decorationSpec.block && to === doc.length)
|
||||
decorationSpec.inclusiveEnd = false;
|
||||
return import_view.Decoration.replace(decorationSpec);
|
||||
};
|
||||
let mathBegin = -1;
|
||||
let mathContentBegin = -1;
|
||||
let block = false;
|
||||
tree.iterate({
|
||||
enter(node) {
|
||||
if (node.name.contains("formatting-math-begin")) {
|
||||
mathBegin = node.from;
|
||||
mathContentBegin = node.to;
|
||||
block = node.name.contains("math-block");
|
||||
} else if (mathBegin !== -1) {
|
||||
if (node.name.contains("formatting-math-end")) {
|
||||
const mathContentEnd = node.from;
|
||||
const mathEnd = node.to;
|
||||
let math = doc.sliceString(mathContentBegin, mathContentEnd);
|
||||
const quote = getQuoteInfo(state, mathContentBegin);
|
||||
if (quote)
|
||||
math = quote.correctMath(math);
|
||||
const widget = new BuiltInMathWidget(math, block);
|
||||
if (quote)
|
||||
widget.markAsCorrected();
|
||||
widget.setPos(
|
||||
block && math.startsWith("\n") ? mathContentBegin + 1 : mathContentBegin,
|
||||
block && math.endsWith("\n") ? mathContentEnd - 1 : mathContentEnd
|
||||
);
|
||||
const overlap = rangesHaveOverlap(ranges, mathBegin, mathEnd);
|
||||
if (block && quote && quote.level > 0) {
|
||||
if (isSourceMode || quote.isBaseCallout || overlap) {
|
||||
const lineBegin = state.doc.lineAt(mathBegin);
|
||||
const lineEnd = state.doc.lineAt(mathEnd);
|
||||
for (let i = lineBegin.number; i <= lineEnd.number; i++) {
|
||||
const line = state.doc.line(i);
|
||||
decorations.push(
|
||||
import_view.Decoration.line({ class: "HyperMD-quote" }).range(line.from, line.from)
|
||||
);
|
||||
const transparent = !isSourceMode && !rangesHaveOverlap(ranges, line.from, line.to);
|
||||
let start = 0;
|
||||
for (let i2 = 0; i2 < quote.level; i2++) {
|
||||
const index = line.text.indexOf(">", start);
|
||||
if (index === -1)
|
||||
continue;
|
||||
const pos = index + line.from;
|
||||
if (i2 === 0) {
|
||||
decorations.push(
|
||||
import_view.Decoration.mark({ class: transparent ? "cm-transparent" : "cm-quote cm-formatting-quote" }).range(pos, pos + 1)
|
||||
);
|
||||
} else {
|
||||
decorations.push(
|
||||
import_view.Decoration.mark({ class: transparent ? "cm-blockquote-border cm-transparent" : "cm-quote cm-formatting-quote" }).range(pos, pos + 1)
|
||||
);
|
||||
}
|
||||
start = index + 1;
|
||||
}
|
||||
}
|
||||
if (lineEnd.from < mathContentEnd && lineEnd.text.slice(0, mathContentEnd - lineEnd.from).split(">").every((s) => !s.trim())) {
|
||||
decorations.push(
|
||||
import_view.Decoration.mark({ class: "cancel-cm-math" }).range(lineEnd.from, mathContentEnd)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!isSourceMode && (quote == null ? void 0 : quote.isBaseCallout)) {
|
||||
if (overlap) {
|
||||
if (block) {
|
||||
decorations.push(
|
||||
import_view.Decoration.widget({
|
||||
widget,
|
||||
block: false,
|
||||
side: 1
|
||||
}).range(mathEnd, mathEnd)
|
||||
);
|
||||
}
|
||||
} else {
|
||||
decorations.push(
|
||||
makeDeco({
|
||||
widget,
|
||||
block: false
|
||||
}, mathBegin, mathEnd).range(mathBegin, mathEnd)
|
||||
);
|
||||
}
|
||||
}
|
||||
mathBegin = -1;
|
||||
mathContentBegin = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return import_view.Decoration.set(decorations, true);
|
||||
},
|
||||
provide(field) {
|
||||
return import_view.EditorView.decorations.from(field);
|
||||
}
|
||||
});
|
||||
|
||||
// src/patch-widget-type.ts
|
||||
var import_view2 = require("@codemirror/view");
|
||||
var import_view3 = require("@codemirror/view");
|
||||
|
||||
// node_modules/monkey-around/mjs/index.js
|
||||
function around(obj, factories) {
|
||||
const removers = Object.keys(factories).map((key) => around1(obj, key, factories[key]));
|
||||
return removers.length === 1 ? removers[0] : function() {
|
||||
removers.forEach((r) => r());
|
||||
};
|
||||
}
|
||||
function around1(obj, method, createWrapper) {
|
||||
const original = obj[method], hadOwn = obj.hasOwnProperty(method);
|
||||
let current = createWrapper(original);
|
||||
if (original)
|
||||
Object.setPrototypeOf(current, original);
|
||||
Object.setPrototypeOf(wrapper, current);
|
||||
obj[method] = wrapper;
|
||||
return remove;
|
||||
function wrapper(...args) {
|
||||
if (current === original && obj[method] === wrapper)
|
||||
remove();
|
||||
return current.apply(this, args);
|
||||
}
|
||||
function remove() {
|
||||
if (obj[method] === wrapper) {
|
||||
if (hadOwn)
|
||||
obj[method] = original;
|
||||
else
|
||||
delete obj[method];
|
||||
}
|
||||
if (current === original)
|
||||
return;
|
||||
current = original;
|
||||
Object.setPrototypeOf(wrapper, original || Function);
|
||||
}
|
||||
}
|
||||
|
||||
// src/patch-widget-type.ts
|
||||
var patchDecoration = (plugin, onPatched) => {
|
||||
const uninstaller = around(import_view2.Decoration, {
|
||||
replace(old) {
|
||||
return function(spec) {
|
||||
if (!plugin.patchSucceeded && spec.widget) {
|
||||
plugin.patchSucceeded = patchMathWidget(plugin, spec.widget);
|
||||
if (plugin.patchSucceeded) {
|
||||
onPatched(spec.widget.constructor);
|
||||
uninstaller();
|
||||
}
|
||||
}
|
||||
return old.call(this, spec);
|
||||
};
|
||||
},
|
||||
widget(old) {
|
||||
return function(spec) {
|
||||
if (!plugin.patchSucceeded && spec.widget) {
|
||||
plugin.patchSucceeded = patchMathWidget(plugin, spec.widget);
|
||||
if (plugin.patchSucceeded) {
|
||||
onPatched(spec.widget.constructor);
|
||||
uninstaller();
|
||||
}
|
||||
}
|
||||
return old.call(this, spec);
|
||||
};
|
||||
}
|
||||
});
|
||||
plugin.register(uninstaller);
|
||||
};
|
||||
function patchMathWidget(plugin, widget) {
|
||||
const proto = widget.constructor.prototype;
|
||||
const superProto = Object.getPrototypeOf(proto);
|
||||
const superSuperProto = Object.getPrototypeOf(superProto);
|
||||
const isObsidianBuiltinMathWidget = Object.hasOwn(widget, "math") && Object.hasOwn(widget, "block") && Object.hasOwn(proto, "eq") && Object.hasOwn(proto, "initDOM") && Object.hasOwn(proto, "patchDOM") && Object.hasOwn(proto, "render") && !Object.hasOwn(proto, "toDOM") && !Object.hasOwn(proto, "updateDOM") && Object.hasOwn(superProto, "become") && Object.hasOwn(superProto, "updateDOM") && Object.hasOwn(superSuperProto, "addEditButton") && Object.hasOwn(superSuperProto, "hookClickHandler") && Object.hasOwn(superSuperProto, "resizeWidget") && Object.hasOwn(superSuperProto, "setOwner") && Object.hasOwn(superSuperProto, "setPos") && Object.hasOwn(superSuperProto, "toDOM") && Object.getPrototypeOf(superSuperProto) === import_view3.WidgetType.prototype;
|
||||
if (isObsidianBuiltinMathWidget) {
|
||||
plugin.register(around(proto, {
|
||||
/** Newly added by this plugin: Get a quote info for the position of this math widget. */
|
||||
getQuoteInfo() {
|
||||
return function() {
|
||||
return this.view ? getQuoteInfo(this.view.state, this.start - 1) : null;
|
||||
};
|
||||
},
|
||||
/** Newly added by this plugin */
|
||||
markAsCorrected() {
|
||||
return function() {
|
||||
this.corrected = true;
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Newly added by this plugin: Correct the LaTeX source code (this.math)
|
||||
* based on the quote info, i.e. remove an appropreate number of ">"s
|
||||
* at the head of each line.
|
||||
*/
|
||||
correctIfNecessary() {
|
||||
return function() {
|
||||
if (this.block && !this.corrected) {
|
||||
const quote = this.getQuoteInfo();
|
||||
if (quote) {
|
||||
this.math = quote.correctMath(this.math);
|
||||
this.markAsCorrected();
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
eq(old) {
|
||||
return function(other) {
|
||||
if (this.block && other.block) {
|
||||
if (this.view && !other.view)
|
||||
other.view = this.view;
|
||||
if (other.view && !this.view)
|
||||
this.view = other.view;
|
||||
if (!this.corrected)
|
||||
this.correctIfNecessary();
|
||||
if (!other.corrected)
|
||||
other.correctIfNecessary();
|
||||
}
|
||||
return old.call(this, other);
|
||||
};
|
||||
},
|
||||
initDOM(old) {
|
||||
return function(view) {
|
||||
if (!this.view)
|
||||
this.view = view;
|
||||
return old.call(this, view);
|
||||
};
|
||||
},
|
||||
patchDOM(old) {
|
||||
return function(dom, view) {
|
||||
if (!this.view)
|
||||
this.view = view;
|
||||
return old.call(this, dom, view);
|
||||
};
|
||||
},
|
||||
render(old) {
|
||||
return function(dom) {
|
||||
this.correctIfNecessary();
|
||||
old.call(this, dom);
|
||||
};
|
||||
}
|
||||
}));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// src/settings.ts
|
||||
var import_obsidian2 = require("obsidian");
|
||||
var DEFAULT_SETTINGS = {
|
||||
notification: true
|
||||
};
|
||||
var MathInCalloutSettingTab = class extends import_obsidian2.PluginSettingTab {
|
||||
constructor(plugin) {
|
||||
super(plugin.app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
display() {
|
||||
this.containerEl.empty();
|
||||
new import_obsidian2.Setting(this.containerEl).setDesc("If something is not working, type some math expression outside callouts in Live Preview.");
|
||||
new import_obsidian2.Setting(this.containerEl).setName("Show setup guidance notifications").addToggle((toggle) => {
|
||||
toggle.setValue(this.plugin.settings.notification).onChange(async (value) => {
|
||||
this.plugin.settings.notification = value;
|
||||
await this.plugin.saveSettings();
|
||||
this.plugin.showNotReadyNotice();
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// src/main.ts
|
||||
var MathInCalloutPlugin = class extends import_obsidian3.Plugin {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
this.notReadyNotice = null;
|
||||
}
|
||||
async onload() {
|
||||
await this.loadSettings();
|
||||
await this.saveSettings();
|
||||
this.addSettingTab(new MathInCalloutSettingTab(this));
|
||||
this.patchSucceeded = false;
|
||||
this.registerEditorExtension(quoteInfoField);
|
||||
this.app.workspace.onLayoutReady(() => setTimeout(() => this.showNotReadyNotice(), 1e3));
|
||||
patchDecoration(this, (builtInMathWidget) => {
|
||||
setTimeout(() => {
|
||||
if (this.notReadyNotice) {
|
||||
this.notReadyNotice.hide();
|
||||
this.notReadyNotice = null;
|
||||
if (this.settings.notification) {
|
||||
new import_obsidian3.Notice(`${this.manifest.name}: You're ready! (Note: this notifiction can be turned off in the plugin setting.)`, 1500);
|
||||
}
|
||||
}
|
||||
this.registerEditorExtension(createCalloutDecorator(builtInMathWidget));
|
||||
this.rerender();
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
rerender() {
|
||||
this.app.workspace.iterateAllLeaves((leaf) => {
|
||||
if (leaf.view instanceof import_obsidian3.MarkdownView) {
|
||||
const eState = leaf.view.getEphemeralState();
|
||||
const editor = leaf.view.editor;
|
||||
editor.setValue(editor.getValue());
|
||||
leaf.view.setEphemeralState(eState);
|
||||
}
|
||||
});
|
||||
}
|
||||
showNotReadyNotice() {
|
||||
if (!this.patchSucceeded && this.settings.notification) {
|
||||
this.notReadyNotice = new import_obsidian3.Notice(`${this.manifest.name}: You're not ready yet. In Live Preview, type some math expression outside callouts.`, 0);
|
||||
}
|
||||
}
|
||||
async loadSettings() {
|
||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
||||
}
|
||||
async saveSettings() {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
};
|
11
.obsidian/plugins/math-in-callout/manifest.json
vendored
Normal file
11
.obsidian/plugins/math-in-callout/manifest.json
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"id": "math-in-callout",
|
||||
"name": "Better Math in Callouts & Blockquotes",
|
||||
"version": "0.3.7",
|
||||
"minAppVersion": "1.3.15",
|
||||
"description": "Add better Live Preview support for math rendering inside callouts & blockquotes.",
|
||||
"author": "Ryota Ushio",
|
||||
"authorUrl": "https://github.com/RyotaUshio",
|
||||
"fundingUrl": "https://www.buymeacoffee.com/ryotaushio",
|
||||
"isDesktopOnly": false
|
||||
}
|
9
.obsidian/plugins/math-in-callout/styles.css
vendored
Normal file
9
.obsidian/plugins/math-in-callout/styles.css
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
/* .cm-math:has(.cm-quote.cm-formatting-quote) */
|
||||
/* .cm-math:has(.cm-blockquote-border) */
|
||||
/* { */
|
||||
/* all: unset; */
|
||||
/* } */
|
||||
|
||||
.cm-math:has( .cancel-cm-math) {
|
||||
all: unset;
|
||||
}
|
Reference in New Issue
Block a user