device-60.home 2025-9-9:23:57:54
This commit is contained in:
828
.obsidian/plugins/obsidian-asciimath/main.js
vendored
828
.obsidian/plugins/obsidian-asciimath/main.js
vendored
@@ -644,178 +644,9 @@ var F = class {
|
||||
}
|
||||
};
|
||||
|
||||
// node_modules/.pnpm/ts-dedent@2.2.0/node_modules/ts-dedent/esm/index.js
|
||||
function dedent(templ) {
|
||||
var values = [];
|
||||
for (var _i = 1; _i < arguments.length; _i++) {
|
||||
values[_i - 1] = arguments[_i];
|
||||
}
|
||||
var strings = Array.from(typeof templ === "string" ? [templ] : templ);
|
||||
strings[strings.length - 1] = strings[strings.length - 1].replace(/\r?\n([\t ]*)$/, "");
|
||||
var indentLengths = strings.reduce(function(arr, str) {
|
||||
var matches = str.match(/\n([\t ]+|(?!\s).)/g);
|
||||
if (matches) {
|
||||
return arr.concat(matches.map(function(match) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = match.match(/[\t ]/g)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
|
||||
}));
|
||||
}
|
||||
return arr;
|
||||
}, []);
|
||||
if (indentLengths.length) {
|
||||
var pattern_1 = new RegExp("\n[ ]{" + Math.min.apply(Math, indentLengths) + "}", "g");
|
||||
strings = strings.map(function(str) {
|
||||
return str.replace(pattern_1, "\n");
|
||||
});
|
||||
}
|
||||
strings[0] = strings[0].replace(/^\r?\n/, "");
|
||||
var string = strings[0];
|
||||
values.forEach(function(value, i) {
|
||||
var endentations = string.match(/(?:^|\n)( *)$/);
|
||||
var endentation = endentations ? endentations[1] : "";
|
||||
var indentedValue = value;
|
||||
if (typeof value === "string" && value.includes("\n")) {
|
||||
indentedValue = String(value).split("\n").map(function(str, i2) {
|
||||
return i2 === 0 ? str : "" + endentation + str;
|
||||
}).join("\n");
|
||||
}
|
||||
string += indentedValue + strings[i + 1];
|
||||
});
|
||||
return string;
|
||||
}
|
||||
var esm_default = dedent;
|
||||
|
||||
// src/confirm-modal.ts
|
||||
var import_obsidian = require("obsidian");
|
||||
var ConfirmModal = class extends import_obsidian.Modal {
|
||||
constructor(app) {
|
||||
super(app);
|
||||
}
|
||||
setMessage(message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
onConfirm(f2) {
|
||||
this.confirmHandler = f2;
|
||||
return this;
|
||||
}
|
||||
onOpen() {
|
||||
const { contentEl, titleEl } = this;
|
||||
titleEl.setText("Are you sure?");
|
||||
new import_obsidian.Setting(contentEl).setDesc(this.message);
|
||||
new import_obsidian.Setting(contentEl).addButton((btn) => btn.setButtonText("Cancel").onClick(() => {
|
||||
this.close();
|
||||
})).addButton((btn) => btn.setButtonText("Continue").setCta().onClick(() => {
|
||||
this.close();
|
||||
this.confirmHandler();
|
||||
}));
|
||||
}
|
||||
onClose() {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
};
|
||||
|
||||
// src/inline.ts
|
||||
var import_language = require("@codemirror/language");
|
||||
var import_view = require("@codemirror/view");
|
||||
var import_obsidian2 = require("obsidian");
|
||||
|
||||
// src/utils.ts
|
||||
function normalizeEscape(escape_) {
|
||||
return escape_.replace(/([$^\\.()[\]{}*?|])/g, "\\$1");
|
||||
}
|
||||
function isLatexCode(code) {
|
||||
const latexRegex = /\\([A-Za-z0-9]){2,}/gm;
|
||||
const texEmbedRegex = /tex".*"/;
|
||||
return latexRegex.test(code) && !texEmbedRegex.test(code);
|
||||
}
|
||||
|
||||
// src/inline.ts
|
||||
var AM = new F();
|
||||
function selectionAndRangeOverlap(selection, rangeFrom, rangeTo) {
|
||||
for (const range of selection.ranges) {
|
||||
if (range.from <= rangeTo && range.to >= rangeFrom)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function inlineRender(view, plugin) {
|
||||
const currentFile = plugin.app.workspace.getActiveFile();
|
||||
if (!currentFile)
|
||||
return;
|
||||
const widgets = [];
|
||||
const selection = view.state.selection;
|
||||
const regex = /.*?_?inline-code_?.*/;
|
||||
for (const { from, to } of view.visibleRanges) {
|
||||
(0, import_language.syntaxTree)(view.state).iterate({
|
||||
from,
|
||||
to,
|
||||
enter: (node) => {
|
||||
const type = node.type;
|
||||
if (type.name.includes("formatting"))
|
||||
return;
|
||||
if (!regex.test(type.name))
|
||||
return;
|
||||
const start = node.from;
|
||||
const end = node.to;
|
||||
const { open, close } = plugin.settings.inline;
|
||||
if (selectionAndRangeOverlap(selection, start - open.length + 1, end + close.length - 1))
|
||||
return;
|
||||
const original = view.state.doc.sliceString(start - open.length + 1, end + close.length - 1).trim();
|
||||
const regex2 = new RegExp(`^${normalizeEscape(open)}(.*?)${normalizeEscape(close)}$`);
|
||||
const matches = original.match(regex2);
|
||||
if (!matches)
|
||||
return;
|
||||
widgets.push(import_view.Decoration.replace({
|
||||
widget: new InlineWidget(matches[1], view),
|
||||
inclusive: false,
|
||||
block: false
|
||||
}).range(start - 1, end + 1));
|
||||
}
|
||||
});
|
||||
}
|
||||
return import_view.Decoration.set(widgets, true);
|
||||
}
|
||||
var InlineWidget = class extends import_view.WidgetType {
|
||||
constructor(rawQuery, view) {
|
||||
super();
|
||||
this.rawQuery = rawQuery;
|
||||
this.view = view;
|
||||
}
|
||||
eq(other) {
|
||||
if (other.rawQuery === this.rawQuery)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
toDOM(_view) {
|
||||
const tex = AM.toTex(this.rawQuery);
|
||||
const mathEl = (0, import_obsidian2.renderMath)(tex, false);
|
||||
(0, import_obsidian2.finishRenderMath)();
|
||||
return mathEl;
|
||||
}
|
||||
};
|
||||
function inlinePlugin(plugin) {
|
||||
return import_view.ViewPlugin.fromClass(class {
|
||||
constructor(view) {
|
||||
var _a;
|
||||
this.decorations = (_a = inlineRender(view, plugin)) != null ? _a : import_view.Decoration.none;
|
||||
}
|
||||
update(update) {
|
||||
var _a;
|
||||
if (!update.state.field(import_obsidian2.editorLivePreviewField)) {
|
||||
this.decorations = import_view.Decoration.none;
|
||||
return;
|
||||
}
|
||||
if (update.docChanged || update.viewportChanged || update.selectionSet)
|
||||
this.decorations = (_a = inlineRender(update.view, plugin)) != null ? _a : import_view.Decoration.none;
|
||||
}
|
||||
}, { decorations: (v2) => v2.decorations });
|
||||
}
|
||||
|
||||
// src/settings.ts
|
||||
var import_obsidian3 = require("obsidian");
|
||||
var AsciiMathSettingTab = class extends import_obsidian3.PluginSettingTab {
|
||||
var import_obsidian = require("obsidian");
|
||||
var AsciiMathSettingTab = class extends import_obsidian.PluginSettingTab {
|
||||
constructor(app, plugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
@@ -824,37 +655,25 @@ var AsciiMathSettingTab = class extends import_obsidian3.PluginSettingTab {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
containerEl.createEl("h2", { text: "Settings for asciimath" });
|
||||
new import_obsidian3.Setting(containerEl).setName("Code block prefix aliases").setDesc("Seperate different aliases with comma.").addText((text) => text.setPlaceholder("asciimath, am").setValue(this.plugin.settings.blockPrefix.join(", ")).onChange((0, import_obsidian3.debounce)((value) => {
|
||||
new import_obsidian.Setting(containerEl).setName("Code block prefix aliases").setDesc("Seperate different aliases with comma.").addText((text) => text.setPlaceholder("asciimath, am").setValue(this.plugin.settings.blockPrefix.join(", ")).onChange((0, import_obsidian.debounce)((value) => {
|
||||
this.plugin.settings.blockPrefix = value.split(",").map((s) => s.trim()).filter(Boolean);
|
||||
}, 1e3)));
|
||||
new import_obsidian3.Setting(containerEl).setName("Replace math blocks").setDesc("Enable this if you want to use AsciiMath but keep using default math blocks (dollar-sign blocks). This will not affect your previous notes that are written in LaTeX because the plugin will check which syntax to use before drawing the math.").addToggle((toggle) => {
|
||||
new import_obsidian.Setting(containerEl).setName("Replace math blocks").setDesc("Enable this if you want to use AsciiMath but keep using default math blocks (dollar-sign blocks). This will not affect your previous notes that are written in LaTeX because the plugin will check which syntax to use before drawing the math.").addToggle((toggle) => {
|
||||
toggle.setValue(this.plugin.settings.replaceMathBlock).onChange((v2) => {
|
||||
this.plugin.settings.replaceMathBlock = v2;
|
||||
this.plugin.setupMathBlockRendering();
|
||||
});
|
||||
});
|
||||
new import_obsidian3.Setting(containerEl).setName("Custom symbols").setDesc("Transforms custom symbols into LaTeX symbols. One row for each rule.").addTextArea((text) => {
|
||||
const el = text.setPlaceholder("symbol1, \\LaTeXSymbol1\nsymbol2, \\LaTeXSymbol2\n...").setValue(this.plugin.settings.customSymbols.map((r) => r.join(", ")).join("\n")).onChange((0, import_obsidian3.debounce)((value) => {
|
||||
new import_obsidian.Setting(containerEl).setName("Custom symbols").setDesc("Transforms custom symbols into LaTeX symbols. One row for each rule.").addTextArea((text) => {
|
||||
const el = text.setPlaceholder("symbol1, \\LaTeXSymbol1\nsymbol2, \\LaTeXSymbol2\n...").setValue(this.plugin.settings.customSymbols.map((r) => r.join(", ")).join("\n")).onChange((0, import_obsidian.debounce)((value) => {
|
||||
this.plugin.settings.customSymbols = value.split("\n").map((r) => r.split(",").map((s) => s.trim()).filter(Boolean)).filter((l) => l.length);
|
||||
}, 1e3));
|
||||
el.inputEl.addClass("__asciimath_settings_custom-symbols");
|
||||
});
|
||||
new import_obsidian3.Setting(containerEl).setHeading().setName("Inline code math (deprecated)").setDesc("These settings will be removed in the next version of the plugin");
|
||||
new import_obsidian3.Setting(containerEl).setName("Disable deprecation warning").setDesc("Note: ignoring deprecation issues may make the plugin unusable with existing notes in the future.").addToggle((toggle) => {
|
||||
toggle.setValue(this.plugin.settings.disableDeprecationWarning).onChange((v2) => {
|
||||
this.plugin.settings.disableDeprecationWarning = v2;
|
||||
});
|
||||
});
|
||||
new import_obsidian3.Setting(containerEl).setName("Inline asciimath start").setDesc("The leading escape of the inline asciimath formula. It should starts with **only one backtick**.").addText((text) => text.setPlaceholder("`$").setValue(this.plugin.settings.inline.open).onChange((0, import_obsidian3.debounce)((value) => {
|
||||
this.plugin.settings.inline.open = value;
|
||||
}, 1e3)));
|
||||
new import_obsidian3.Setting(containerEl).setName("Inline asciimath end").setDesc("The trailing escape of the inline asciimath formula. It should ends with **only one backtick**.").addText((text) => text.setPlaceholder("$`").setValue(this.plugin.settings.inline.close).onChange((0, import_obsidian3.debounce)((value) => {
|
||||
this.plugin.settings.inline.close = value;
|
||||
}, 1e3)));
|
||||
new import_obsidian3.Setting(containerEl).setName("Don't forget to save and reload settings \u2192").addButton((btn) => btn.setButtonText("Save").onClick(async () => {
|
||||
new import_obsidian.Setting(containerEl).setName("Don't forget to save and reload settings \u2192").addButton((btn) => btn.setButtonText("Save").onClick(async () => {
|
||||
const valid = validateSettings(this.plugin.settings);
|
||||
if (!valid.isValid) {
|
||||
new import_obsidian3.Notice(valid.message);
|
||||
new import_obsidian.Notice(valid.message);
|
||||
return;
|
||||
}
|
||||
await this.plugin.saveSettings();
|
||||
@@ -866,7 +685,7 @@ var AsciiMathSettingTab = class extends import_obsidian3.PluginSettingTab {
|
||||
this.plugin.AM = new F({
|
||||
symbols: this.plugin.calcSymbols()
|
||||
});
|
||||
new import_obsidian3.Notice("Asciimath settings reloaded successfully!");
|
||||
new import_obsidian.Notice("Asciimath settings reloaded successfully!");
|
||||
}));
|
||||
}
|
||||
};
|
||||
@@ -877,19 +696,6 @@ function validateSettings(settings) {
|
||||
message: "You should add at least 1 block prefix!"
|
||||
};
|
||||
}
|
||||
const { open, close } = settings.inline;
|
||||
if (!open.startsWith("`") || open.length <= 1 || open.startsWith("``")) {
|
||||
return {
|
||||
isValid: false,
|
||||
message: "Invalid inline leading escape!"
|
||||
};
|
||||
}
|
||||
if (!close.endsWith("`") || close.length <= 1 || close.endsWith("``")) {
|
||||
return {
|
||||
isValid: false,
|
||||
message: "Invalid inline trailing escape!"
|
||||
};
|
||||
}
|
||||
const { customSymbols } = settings;
|
||||
if (customSymbols.find((pair) => pair.length !== 2)) {
|
||||
return {
|
||||
@@ -903,8 +709,23 @@ function validateSettings(settings) {
|
||||
};
|
||||
}
|
||||
|
||||
// src/utils.ts
|
||||
function isLatexCode(code) {
|
||||
const latexRegex = /\\([A-Za-z0-9]){2,}/gm;
|
||||
const simpleLatexSupSubRegex = /[\^_]\{\s*[a-zA-Z0-9 ]+\s*\}/g;
|
||||
const texEmbedRegex = /tex".*"/;
|
||||
const hasTrueLatex = latexRegex.test(code);
|
||||
const hasSimpleLatexSupSub = simpleLatexSupSubRegex.test(code);
|
||||
const hasTexEmbed = texEmbedRegex.test(code);
|
||||
return (hasTrueLatex || hasSimpleLatexSupSub && !hasTrueLatex) && !hasTexEmbed;
|
||||
}
|
||||
function toTex(am, content, displayMode) {
|
||||
const tex = am.toTex(content, { display: displayMode });
|
||||
return tex.replace(/(\{|\})(\1+)/g, (...args) => Array(args[2].length + 1).fill(args[1]).join(" "));
|
||||
}
|
||||
|
||||
// src/symbol-search/modal.ts
|
||||
var import_obsidian4 = require("obsidian");
|
||||
var import_obsidian2 = require("obsidian");
|
||||
|
||||
// src/symbol-search/symbols.json
|
||||
var symbols_default = [
|
||||
@@ -1429,7 +1250,7 @@ var symbols_default = [
|
||||
];
|
||||
|
||||
// src/symbol-search/modal.ts
|
||||
var SymbolSearchModal = class extends import_obsidian4.SuggestModal {
|
||||
var SymbolSearchModal = class extends import_obsidian2.SuggestModal {
|
||||
constructor(app, sel, am) {
|
||||
super(app);
|
||||
this.sel = sel;
|
||||
@@ -1477,11 +1298,11 @@ var SymbolSearchModal = class extends import_obsidian4.SuggestModal {
|
||||
toBeRendered = `tex"${toBeRendered}"`;
|
||||
el2.innerHTML = `
|
||||
<mjx-container class="MathJax" jax="CHTML">
|
||||
${(0, import_obsidian4.renderMath)(toBeRendered, true).innerHTML}
|
||||
${(0, import_obsidian2.renderMath)(toBeRendered, true).innerHTML}
|
||||
</mjx-container>
|
||||
`;
|
||||
if (this.renderCount >= this.renderMax)
|
||||
(0, import_obsidian4.finishRenderMath)();
|
||||
(0, import_obsidian2.finishRenderMath)();
|
||||
});
|
||||
}
|
||||
onSelected(cb) {
|
||||
@@ -1492,21 +1313,388 @@ var SymbolSearchModal = class extends import_obsidian4.SuggestModal {
|
||||
}
|
||||
};
|
||||
|
||||
// src/symbol-search/modal-instance.ts
|
||||
function createModalInstance(editor) {
|
||||
const sel = editor.getSelection();
|
||||
const modal = new SymbolSearchModal(this.app, sel, this.AM);
|
||||
modal.setPlaceholder("Start typing AsciiMath or LaTeX symbol name");
|
||||
modal.onSelected((sym) => {
|
||||
var _a;
|
||||
const { am } = sym;
|
||||
if ("placeholder" in sym) {
|
||||
const { placeholder, fill } = sym;
|
||||
let tempExceptFirst = placeholder;
|
||||
for (let i = 2; i <= fill.length; i++)
|
||||
tempExceptFirst = tempExceptFirst.replace(`$${i}`, "");
|
||||
const temp = tempExceptFirst.replace("$1", "");
|
||||
if (!sel) {
|
||||
const cur = editor.getCursor();
|
||||
const placeholder_a_pos = placeholder.indexOf("$1");
|
||||
const spacesBefore$1 = ((_a = placeholder.substring(0, placeholder_a_pos).match(/(\$\d+?)/g)) == null ? void 0 : _a.join("").length) || 0;
|
||||
editor.replaceSelection(am + temp);
|
||||
editor.setCursor({
|
||||
line: cur.line,
|
||||
ch: cur.ch + am.length + placeholder_a_pos - spacesBefore$1
|
||||
});
|
||||
} else {
|
||||
const placeholder_b_pos = placeholder.indexOf("$2");
|
||||
const cur = editor.getCursor("to");
|
||||
editor.replaceSelection(am + tempExceptFirst.replace("$1", sel));
|
||||
if (placeholder_b_pos !== -1) {
|
||||
const $before$2 = placeholder.substring(0, placeholder_b_pos).match(/(\$\d+?)/g);
|
||||
const $spacesBefore$2 = ($before$2 == null ? void 0 : $before$2.join("").length) || 0;
|
||||
const $2before$1 = !$before$2 || !$before$2.includes("$1") ? sel.length : 0;
|
||||
editor.setCursor({
|
||||
line: cur.line,
|
||||
ch: cur.ch + am.length + placeholder_b_pos - $spacesBefore$2 - $2before$1
|
||||
});
|
||||
} else {
|
||||
editor.setCursor({
|
||||
line: cur.line,
|
||||
ch: cur.ch + am.length + placeholder.length - 2
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
editor.replaceSelection(am);
|
||||
}
|
||||
});
|
||||
modal.open();
|
||||
}
|
||||
|
||||
// src/confirm-modal.ts
|
||||
var import_obsidian3 = require("obsidian");
|
||||
var ConfirmModal = class extends import_obsidian3.Modal {
|
||||
constructor(app) {
|
||||
super(app);
|
||||
}
|
||||
setMessage(message) {
|
||||
this.message = message;
|
||||
return this;
|
||||
}
|
||||
setEnableDisplayMode(enableDisplayMode) {
|
||||
this.enableDisplayMode = enableDisplayMode;
|
||||
return this;
|
||||
}
|
||||
onConfirm(f2) {
|
||||
this.confirmHandler = () => f2(this.enableDisplayMode);
|
||||
return this;
|
||||
}
|
||||
onOpen() {
|
||||
const { contentEl, titleEl } = this;
|
||||
titleEl.setText("Are you sure?");
|
||||
new import_obsidian3.Setting(contentEl).setDesc(this.message);
|
||||
new import_obsidian3.Setting(contentEl).setName("Enable display mode for each formula").setDesc("This option will insert \\display{ ... } for each formula.").addToggle((toggle) => toggle.setValue(this.enableDisplayMode).onChange((value) => {
|
||||
this.enableDisplayMode = value;
|
||||
}));
|
||||
new import_obsidian3.Setting(contentEl).addButton((btn) => btn.setButtonText("Cancel").onClick(() => {
|
||||
this.close();
|
||||
})).addButton((btn) => btn.setButtonText("Continue").setCta().onClick(() => {
|
||||
this.close();
|
||||
this.confirmHandler();
|
||||
}));
|
||||
}
|
||||
onClose() {
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
};
|
||||
|
||||
// node_modules/.pnpm/ts-dedent@2.2.0/node_modules/ts-dedent/esm/index.js
|
||||
function dedent(templ) {
|
||||
var values = [];
|
||||
for (var _i = 1; _i < arguments.length; _i++) {
|
||||
values[_i - 1] = arguments[_i];
|
||||
}
|
||||
var strings = Array.from(typeof templ === "string" ? [templ] : templ);
|
||||
strings[strings.length - 1] = strings[strings.length - 1].replace(/\r?\n([\t ]*)$/, "");
|
||||
var indentLengths = strings.reduce(function(arr, str) {
|
||||
var matches = str.match(/\n([\t ]+|(?!\s).)/g);
|
||||
if (matches) {
|
||||
return arr.concat(matches.map(function(match) {
|
||||
var _a, _b;
|
||||
return (_b = (_a = match.match(/[\t ]/g)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0;
|
||||
}));
|
||||
}
|
||||
return arr;
|
||||
}, []);
|
||||
if (indentLengths.length) {
|
||||
var pattern_1 = new RegExp("\n[ ]{" + Math.min.apply(Math, indentLengths) + "}", "g");
|
||||
strings = strings.map(function(str) {
|
||||
return str.replace(pattern_1, "\n");
|
||||
});
|
||||
}
|
||||
strings[0] = strings[0].replace(/^\r?\n/, "");
|
||||
var string = strings[0];
|
||||
values.forEach(function(value, i) {
|
||||
var endentations = string.match(/(?:^|\n)( *)$/);
|
||||
var endentation = endentations ? endentations[1] : "";
|
||||
var indentedValue = value;
|
||||
if (typeof value === "string" && value.includes("\n")) {
|
||||
indentedValue = String(value).split("\n").map(function(str, i2) {
|
||||
return i2 === 0 ? str : "" + endentation + str;
|
||||
}).join("\n");
|
||||
}
|
||||
string += indentedValue + strings[i + 1];
|
||||
});
|
||||
return string;
|
||||
}
|
||||
var esm_default = dedent;
|
||||
|
||||
// src/convertion.ts
|
||||
var import_obsidian4 = require("obsidian");
|
||||
async function convertAsciiMathInFile(plugin, file, display) {
|
||||
const view = plugin.app.workspace.getActiveViewOfType(import_obsidian4.MarkdownView);
|
||||
if (!view)
|
||||
return { block: 0, inline: 0 };
|
||||
const { editor } = view;
|
||||
const cache = plugin.app.metadataCache.getFileCache(file);
|
||||
if (!cache || !cache.sections)
|
||||
return { block: 0, inline: 0 };
|
||||
const formulaBlocks = [];
|
||||
if (cache.sections) {
|
||||
for (const section of cache.sections) {
|
||||
const { start, end } = section.position;
|
||||
if (section.type === "math" || section.type === "code") {
|
||||
let content = editor.getRange({ line: start.line, ch: start.col }, { line: end.line, ch: end.col });
|
||||
if (section.type === "math") {
|
||||
content = content.replace(/^\$\$\s*/, "").replace(/\s*\$\$$/, "");
|
||||
}
|
||||
if (section.type === "code") {
|
||||
const blockReg = new RegExp(`((\`|~){3,})(${plugin.settings.blockPrefix.join("|")})([\\s\\S]*?)\\n\\1`, "m");
|
||||
const match = content.match(blockReg);
|
||||
if (match)
|
||||
content = match[4].trim();
|
||||
else
|
||||
continue;
|
||||
}
|
||||
formulaBlocks.push({
|
||||
content,
|
||||
position: section.position,
|
||||
isBlock: true
|
||||
});
|
||||
} else {
|
||||
let content = editor.getRange({ line: start.line, ch: start.col }, { line: end.line, ch: end.col });
|
||||
const inlineMathRegex = /(?<!\$)\$([^$]+?)\$(?!\$)/g;
|
||||
let inlineMatch;
|
||||
while ((inlineMatch = inlineMathRegex.exec(content)) !== null) {
|
||||
const relativeStart = inlineMatch.index;
|
||||
const relativeEnd = relativeStart + inlineMatch[0].length;
|
||||
const absoluteStart = section.position.start.offset + relativeStart;
|
||||
const absoluteEnd = section.position.start.offset + relativeEnd;
|
||||
const startPos = editor.offsetToPos(absoluteStart);
|
||||
const endPos = editor.offsetToPos(absoluteEnd);
|
||||
const amCode = inlineMatch[1].trim();
|
||||
if (isLatexCode(amCode))
|
||||
continue;
|
||||
formulaBlocks.push({
|
||||
position: {
|
||||
start: { line: startPos.line, col: startPos.ch, offset: absoluteStart },
|
||||
end: { line: endPos.line, col: endPos.ch, offset: absoluteEnd }
|
||||
},
|
||||
content: amCode,
|
||||
isBlock: false
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
const changes = [];
|
||||
formulaBlocks.forEach((block) => {
|
||||
const { start, end } = block.position;
|
||||
const res = toTex(plugin.AM, block.content, display);
|
||||
const replacement = block.isBlock ? `$$
|
||||
${res}
|
||||
$$` : `$${res}$`;
|
||||
changes.push({
|
||||
from: { line: start.line, ch: start.col },
|
||||
to: { line: end.line, ch: end.col },
|
||||
text: replacement
|
||||
});
|
||||
});
|
||||
editor.transaction({ changes });
|
||||
new import_obsidian4.Notice(`Conversion completed: ${formulaBlocks.length} formulas processed`);
|
||||
}
|
||||
return {
|
||||
block: formulaBlocks.filter((x) => x.isBlock).length,
|
||||
inline: formulaBlocks.filter((x) => !x.isBlock).length
|
||||
};
|
||||
}
|
||||
async function extractFormulasInFile(plugin, file) {
|
||||
const content = await plugin.app.vault.read(file);
|
||||
const formulas = [];
|
||||
const codeRanges = [];
|
||||
const codeBlockRegex = /(^|\n)(```|~~~)[\s\S]*?\2/g;
|
||||
const amCodeBlockRegex = new RegExp(`([\`~]{3,})(${plugin.settings.blockPrefix.join("|")})([\\s\\S]*?)\\n\\1`, "m");
|
||||
const inlineCodeRegex = /`[^`\n]*`/g;
|
||||
for (const match of content.matchAll(codeBlockRegex)) {
|
||||
const am = match[0].match(amCodeBlockRegex);
|
||||
codeRanges.push({
|
||||
start: match.index,
|
||||
end: match.index + match[0].length,
|
||||
isAm: am !== null
|
||||
});
|
||||
if (am) {
|
||||
const amCode = am[3];
|
||||
let start = match.index;
|
||||
if (match[1] === "\n") {
|
||||
start += 1;
|
||||
}
|
||||
formulas.push({
|
||||
type: "block",
|
||||
start,
|
||||
end: match.index + match[0].length,
|
||||
content: amCode
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const match of content.matchAll(inlineCodeRegex)) {
|
||||
codeRanges.push({
|
||||
start: match.index,
|
||||
end: match.index + match[0].length,
|
||||
isAm: false
|
||||
});
|
||||
}
|
||||
const inlineRegex = /(?<![\\\$])\$([^$]+?)\$/g;
|
||||
const blockRegex = /(?<!\\)\$\$([\s\S]+?)\$\$/g;
|
||||
for (const match of content.matchAll(inlineRegex)) {
|
||||
if (!isLatexCode(match[1])) {
|
||||
formulas.push({
|
||||
type: "inline",
|
||||
start: match.index,
|
||||
end: match.index + match[0].length,
|
||||
content: match[1].trim()
|
||||
});
|
||||
}
|
||||
}
|
||||
for (const match of content.matchAll(blockRegex)) {
|
||||
if (!isLatexCode(match[1])) {
|
||||
formulas.push({
|
||||
type: "block",
|
||||
start: match.index,
|
||||
end: match.index + match[0].length,
|
||||
content: match[1].trim()
|
||||
});
|
||||
}
|
||||
}
|
||||
return formulas.filter((formula) => {
|
||||
return !codeRanges.some((range) => formula.start >= range.start && formula.end <= range.end && !range.isAm);
|
||||
});
|
||||
}
|
||||
async function replaceFormulasInFile(plugin, file, enableDisplayMode) {
|
||||
const content = await plugin.app.vault.read(file);
|
||||
const formulas = await extractFormulasInFile(plugin, file);
|
||||
console.log({ formulas });
|
||||
formulas.sort((a, b2) => b2.start - a.start);
|
||||
let newContent = content;
|
||||
const convertedCnt = { block: 0, inline: 0 };
|
||||
for (const formula of formulas) {
|
||||
if (isLatexCode(formula.content)) {
|
||||
continue;
|
||||
}
|
||||
const converted = toTex(plugin.AM, formula.content.trim(), enableDisplayMode);
|
||||
const replacement = formula.type === "inline" ? `$${converted}$` : `$$${converted}$$`;
|
||||
newContent = newContent.substring(0, formula.start) + replacement + newContent.substring(formula.end);
|
||||
convertedCnt[formula.type] += 1;
|
||||
}
|
||||
await plugin.app.vault.modify(file, newContent);
|
||||
return convertedCnt;
|
||||
}
|
||||
function actionConvertActiveFile(plugin, message) {
|
||||
return async () => new ConfirmModal(plugin.app).setMessage(message).setEnableDisplayMode(false).onConfirm(async (displayMode) => {
|
||||
const file = plugin.app.workspace.getActiveFile();
|
||||
if (!file) {
|
||||
new import_obsidian4.Notice("No active file found.");
|
||||
return;
|
||||
}
|
||||
await convertAsciiMathInFile(plugin, file, displayMode);
|
||||
}).open();
|
||||
}
|
||||
function actionConvertEntireVault(plugin, message) {
|
||||
return async () => new ConfirmModal(plugin.app).setMessage(message).setEnableDisplayMode(false).onConfirm(async (displayMode) => {
|
||||
const allConvertionRes = await Promise.all(plugin.app.vault.getMarkdownFiles().map(async (f2) => {
|
||||
const convertionRes = await replaceFormulasInFile(plugin, f2, displayMode);
|
||||
return {
|
||||
...convertionRes,
|
||||
hasAsciimath: convertionRes.block || convertionRes.inline
|
||||
};
|
||||
}));
|
||||
const lo = { block: 0, inline: 0, fileNum: 0 };
|
||||
allConvertionRes.forEach((res) => {
|
||||
if (res.hasAsciimath) {
|
||||
lo.block += res.block;
|
||||
lo.inline += res.inline;
|
||||
lo.fileNum += 1;
|
||||
}
|
||||
});
|
||||
new import_obsidian4.Notice(`Converted ${lo.block} blocks and ${lo.inline} inline formulas in ${lo.fileNum} file${lo.fileNum > 1 ? "s" : ""}.`);
|
||||
}).open();
|
||||
}
|
||||
|
||||
// src/commands.ts
|
||||
function initCommands(plugin) {
|
||||
const commands = [
|
||||
{
|
||||
id: "asciimath-insert-symbol",
|
||||
icon: "sigma",
|
||||
name: "View AsciiMath symbols",
|
||||
editorCallback: (editor) => {
|
||||
createModalInstance(editor);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "insert-asciimath-block",
|
||||
name: "Insert asciimath block",
|
||||
editorCallback: (editor, _view) => {
|
||||
editor.replaceSelection(`\`\`\`${plugin.settings.blockPrefix[0] || "asciimath"}
|
||||
${editor.getDoc().getSelection()}
|
||||
\`\`\``);
|
||||
const cursor = editor.getCursor();
|
||||
editor.setCursor(cursor.line - 1);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "convert-selected-to-latex",
|
||||
name: "Convert exact selection into LaTeX",
|
||||
editorCallback: (editor, _view) => {
|
||||
const cursorStart = editor.getCursor("from");
|
||||
const cursorEnd = editor.getCursor("to");
|
||||
const amCode = editor.getSelection();
|
||||
const doConvert = () => editor.replaceRange(plugin.AM.toTex(amCode), cursorStart, cursorEnd);
|
||||
if (amCode.length > 1e3) {
|
||||
new ConfirmModal(plugin.app).setMessage(esm_default`The selection is over 1000 chars.
|
||||
Please confirm that you have selected the exact AsciiMath expression.
|
||||
Click the Continue button to convert though.`).onConfirm(doConvert).open();
|
||||
} else if (isLatexCode(amCode)) {
|
||||
new ConfirmModal(plugin.app).setMessage(esm_default`The selection may be already LaTeX.
|
||||
Click the Continue buttom to convert though.`).onConfirm(doConvert).open();
|
||||
} else {
|
||||
doConvert();
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "convert-am-block-into-mathjax-in-current-file",
|
||||
name: "Convert AsciiMath to LaTeX (active file)",
|
||||
callback: actionConvertActiveFile(plugin, "This will replace all AsciiMath blocks with LaTeX math blocks in the active file. THIS ACTION CANNOT BE UNDONE.")
|
||||
},
|
||||
{
|
||||
id: "convert-am-block-into-mathjax-in-vault",
|
||||
name: "Convert AsciiMath to LaTeX (entire vault)",
|
||||
callback: actionConvertEntireVault(plugin, "This will replace all AsciiMath formulas with LaTeX math blocks in the entire vault. THIS ACTION CANNOT BE UNDONE.")
|
||||
}
|
||||
];
|
||||
commands.forEach((command) => {
|
||||
plugin.addCommand(command);
|
||||
});
|
||||
}
|
||||
|
||||
// src/main.ts
|
||||
var DEFAULT_SETTINGS = {
|
||||
blockPrefix: ["asciimath", "am"],
|
||||
disableDeprecationWarning: false,
|
||||
replaceMathBlock: true,
|
||||
inline: {
|
||||
open: "`$",
|
||||
close: "$`"
|
||||
},
|
||||
customSymbols: []
|
||||
};
|
||||
function toTex(am, content) {
|
||||
const tex = am.toTex(content);
|
||||
return tex.replace(/(\{|\})(\1+)/g, (...args) => Array(args[2].length + 1).fill(args[1]).join(" "));
|
||||
}
|
||||
var AsciiMathPlugin = class extends import_obsidian5.Plugin {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
@@ -1566,86 +1754,7 @@ var AsciiMathPlugin = class extends import_obsidian5.Plugin {
|
||||
new import_obsidian5.Notice("Error: MathJax was not defined despite loading it!");
|
||||
return;
|
||||
}
|
||||
this.app.workspace.on("file-open", async (file) => {
|
||||
if (!file || this.settings.disableDeprecationWarning)
|
||||
return;
|
||||
const content = await this.app.vault.read(file);
|
||||
const [open, close] = Object.values(this.settings.inline).map(normalizeEscape);
|
||||
const inlineReg = new RegExp(`${open}(.*?)${close}`, "g");
|
||||
if (inlineReg.test(content)) {
|
||||
new import_obsidian5.Notice(esm_default`
|
||||
Obsidian AsciiMath:
|
||||
|
||||
Inline math with single backticks is deprecated. Refer to the plugin description to fix this issue.
|
||||
You also can disable this warning in the plugin settings.
|
||||
|
||||
Click here to dismiss this message.
|
||||
`, 0);
|
||||
}
|
||||
});
|
||||
this.addCommand({
|
||||
id: "asciimath-insert-symbol",
|
||||
icon: "sigma",
|
||||
name: "View AsciiMath symbols",
|
||||
editorCallback: this.modalCallback()
|
||||
});
|
||||
this.addCommand({
|
||||
id: "insert-asciimath-block",
|
||||
name: "Insert asciimath block",
|
||||
editorCallback: (editor, _view) => {
|
||||
editor.replaceSelection(`\`\`\`${this.settings.blockPrefix[0] || "asciimath"}
|
||||
${editor.getDoc().getSelection()}
|
||||
\`\`\``);
|
||||
const cursor = editor.getCursor();
|
||||
editor.setCursor(cursor.line - 1);
|
||||
}
|
||||
});
|
||||
this.addCommand({
|
||||
id: "convert-selected-to-latex",
|
||||
name: "Convert exact selection into LaTeX",
|
||||
editorCallback: (editor, _view) => {
|
||||
const cursorStart = editor.getCursor("from");
|
||||
const cursorEnd = editor.getCursor("to");
|
||||
const amCode = editor.getSelection();
|
||||
const doConvert = () => editor.replaceRange(this.AM.toTex(amCode), cursorStart, cursorEnd);
|
||||
if (amCode.length > 500) {
|
||||
new ConfirmModal(this.app).setMessage(esm_default`The selection is over 500 chars.
|
||||
Please confirm that you have selected the exact AsciiMath expression.
|
||||
Click the Continue button to convert though.`).onConfirm(doConvert).open();
|
||||
} else if (isLatexCode(amCode)) {
|
||||
new ConfirmModal(this.app).setMessage(esm_default`The selection may be already LaTeX.
|
||||
Click the Continue buttom to convert though.`).onConfirm(doConvert).open();
|
||||
} else {
|
||||
doConvert();
|
||||
}
|
||||
}
|
||||
});
|
||||
this.addCommand({
|
||||
id: "convert-am-block-into-mathjax-in-current-file",
|
||||
name: "Convert AsciiMath to LaTeX (active file)",
|
||||
callback: this.actionConvertActiveFile("Tex" /* Tex */, "This will replace all AsciiMath blocks with LaTeX math blocks in the active file. THIS ACTION CANNOT BE UNDONE.")
|
||||
});
|
||||
this.addCommand({
|
||||
id: "convert-am-inline-into-new-syntax-in-current-file",
|
||||
name: "Update old AsciiMath (active file)",
|
||||
callback: this.actionConvertActiveFile("Asciimath" /* Asciimath */, esm_default`
|
||||
This will replace all Asciimath formulas of old syntax (like \`\$ and \$\`) with new syntax (wrapped with dollar signs),
|
||||
which is more convenient to use.
|
||||
THIS ACTION CANNOT BE UNDONE.`)
|
||||
});
|
||||
this.addCommand({
|
||||
id: "convert-am-block-into-mathjax-in-vault",
|
||||
name: "Convert AsciiMath to LaTeX (entire vault)",
|
||||
callback: this.actionConvertEntireVault("Tex" /* Tex */, "This will replace all AsciiMath formulas with LaTeX math blocks in the entire vault. THIS ACTION CANNOT BE UNDONE.")
|
||||
});
|
||||
this.addCommand({
|
||||
id: "convert-am-inline-into-new-syntax-in-vault",
|
||||
name: "Update old AsciiMath (entire vault)",
|
||||
callback: this.actionConvertEntireVault("Asciimath" /* Asciimath */, esm_default`
|
||||
This will replace all Asciimath formulas of old syntax (like \`\$ and \$\`) with new syntax (wrapped with dollar signs),
|
||||
which is more convenient to use.
|
||||
THIS ACTION CANNOT BE UNDONE.`)
|
||||
});
|
||||
initCommands(this);
|
||||
this.postProcessors = /* @__PURE__ */ new Map();
|
||||
this.app.workspace.onLayoutReady(async () => {
|
||||
this.settings.blockPrefix.forEach((prefix) => {
|
||||
@@ -1653,139 +1762,10 @@ ${editor.getDoc().getSelection()}
|
||||
this.existPrefixes.push(prefix);
|
||||
});
|
||||
});
|
||||
this.registerEditorExtension([inlinePlugin(this)]);
|
||||
this.registerMarkdownPostProcessor(this.postProcessorInline.bind(this));
|
||||
this.setupMathBlockRendering();
|
||||
this.addSettingTab(new AsciiMathSettingTab(this.app, this));
|
||||
console.log("Obsidian asciimath loaded");
|
||||
}
|
||||
modalCallback() {
|
||||
return (editor) => {
|
||||
const sel = editor.getSelection();
|
||||
const modal = new SymbolSearchModal(this.app, sel, this.AM);
|
||||
modal.setPlaceholder("Start typing AsciiMath or LaTeX symbol name");
|
||||
modal.onSelected((sym) => {
|
||||
var _a;
|
||||
const { am } = sym;
|
||||
if ("placeholder" in sym) {
|
||||
const { placeholder, fill } = sym;
|
||||
let tempExceptFirst = placeholder;
|
||||
for (let i = 2; i <= fill.length; i++)
|
||||
tempExceptFirst = tempExceptFirst.replace(`$${i}`, "");
|
||||
const temp = tempExceptFirst.replace("$1", "");
|
||||
if (!sel) {
|
||||
const cur = editor.getCursor();
|
||||
const placeholder_a_pos = placeholder.indexOf("$1");
|
||||
const spacesBefore$1 = ((_a = placeholder.substring(0, placeholder_a_pos).match(/(\$\d+?)/g)) == null ? void 0 : _a.join("").length) || 0;
|
||||
editor.replaceSelection(am + temp);
|
||||
editor.setCursor({
|
||||
line: cur.line,
|
||||
ch: cur.ch + am.length + placeholder_a_pos - spacesBefore$1
|
||||
});
|
||||
} else {
|
||||
const placeholder_b_pos = placeholder.indexOf("$2");
|
||||
const cur = editor.getCursor("to");
|
||||
editor.replaceSelection(am + tempExceptFirst.replace("$1", sel));
|
||||
if (placeholder_b_pos !== -1) {
|
||||
const $before$2 = placeholder.substring(0, placeholder_b_pos).match(/(\$\d+?)/g);
|
||||
const $spacesBefore$2 = ($before$2 == null ? void 0 : $before$2.join("").length) || 0;
|
||||
const $2before$1 = !$before$2 || !$before$2.includes("$1") ? sel.length : 0;
|
||||
editor.setCursor({
|
||||
line: cur.line,
|
||||
ch: cur.ch + am.length + placeholder_b_pos - $spacesBefore$2 - $2before$1
|
||||
});
|
||||
} else {
|
||||
editor.setCursor({
|
||||
line: cur.line,
|
||||
ch: cur.ch + am.length + placeholder.length - 2
|
||||
});
|
||||
}
|
||||
}
|
||||
} else {
|
||||
editor.replaceSelection(am);
|
||||
}
|
||||
});
|
||||
modal.open();
|
||||
};
|
||||
}
|
||||
actionConvertActiveFile(target, message) {
|
||||
return async () => new ConfirmModal(this.app).setMessage(message).onConfirm(async () => {
|
||||
const file = this.app.workspace.getActiveFile();
|
||||
const { block, inline } = await this.convertAsciiMathInFile(file, target);
|
||||
new import_obsidian5.Notice(`Converted ${block} blocks and ${inline} inline formulas.`);
|
||||
}).open();
|
||||
}
|
||||
actionConvertEntireVault(target, message) {
|
||||
return async () => new ConfirmModal(this.app).setMessage(message).onConfirm(async () => {
|
||||
const allConvertionRes = await Promise.all(this.app.vault.getMarkdownFiles().map(async (f2) => {
|
||||
const convertionRes = await this.convertAsciiMathInFile(f2, target);
|
||||
return {
|
||||
...convertionRes,
|
||||
hasAsciimath: convertionRes.block || convertionRes.inline
|
||||
};
|
||||
}));
|
||||
const { block, inline, fileNum } = allConvertionRes.reduce((x, y) => {
|
||||
return {
|
||||
block: x.block + y.block,
|
||||
inline: x.inline + y.inline,
|
||||
fileNum: x.fileNum + y.hasAsciimath
|
||||
};
|
||||
}, { block: 0, inline: 0, fileNum: 0 });
|
||||
new import_obsidian5.Notice(`Converted ${block} blocks and ${inline} inline formulas in ${fileNum} file${fileNum > 1 ? "s" : ""}.`);
|
||||
}).open();
|
||||
}
|
||||
async convertAsciiMathInFile(file, target) {
|
||||
const convertionRes = { block: 0, inline: 0 };
|
||||
let content = await this.app.vault.read(file);
|
||||
const blockReg = new RegExp(`((\`|~){3,})(${this.settings.blockPrefix.join("|")})([\\s\\S]*?)\\n\\1`, "gm");
|
||||
const [open, close] = Object.values(this.settings.inline).map(normalizeEscape);
|
||||
const inlineReg = new RegExp(`${open}(.*?)${close}`, "g");
|
||||
try {
|
||||
const blockIterator = content.matchAll(blockReg);
|
||||
let match;
|
||||
while (!(match = blockIterator.next()).done) {
|
||||
const block = match.value[0];
|
||||
const blockContent = match.value[4];
|
||||
const innerContent = target === "Tex" /* Tex */ ? toTex(this.AM, blockContent) : blockContent.trim();
|
||||
content = content.replace(block, `$$$$
|
||||
${innerContent}
|
||||
$$$$`);
|
||||
convertionRes.block++;
|
||||
}
|
||||
const inlineBlockIterator = content.matchAll(inlineReg);
|
||||
while (!(match = inlineBlockIterator.next()).done) {
|
||||
const block = match.value[0];
|
||||
const blockContent = match.value[1];
|
||||
const innerContent = target === "Tex" /* Tex */ ? toTex(this.AM, blockContent) : blockContent;
|
||||
content = content.replace(block, `$$${innerContent.trim()}$$`);
|
||||
convertionRes.inline++;
|
||||
}
|
||||
await this.app.vault.modify(file, content);
|
||||
} catch (e) {
|
||||
new import_obsidian5.Notice(String(e));
|
||||
}
|
||||
return convertionRes;
|
||||
}
|
||||
async postProcessorInline(el, _ctx) {
|
||||
const nodeList = el.querySelectorAll("code");
|
||||
if (!nodeList.length)
|
||||
return;
|
||||
for (let i = 0; i < nodeList.length; i++) {
|
||||
const node = nodeList.item(i);
|
||||
if (node.className.trim())
|
||||
continue;
|
||||
let { open, close } = this.settings.inline;
|
||||
open = open.slice(1);
|
||||
close = close.substring(0, close.length - 1);
|
||||
const regex = new RegExp(`^${normalizeEscape(open)}(.*?)${normalizeEscape(close)}$`);
|
||||
const matches = node.innerText.match(regex);
|
||||
if (!matches)
|
||||
continue;
|
||||
const mathEl = (0, import_obsidian5.renderMath)(matches[1], false);
|
||||
(0, import_obsidian5.finishRenderMath)();
|
||||
node.replaceWith(mathEl);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/* nosourcemap */
|
Reference in New Issue
Block a user