455 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			455 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/*
 | 
						|
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");
 | 
						|
    const corrected = lines.map((line) => {
 | 
						|
      const match = line.match(this.pattern);
 | 
						|
      return match ? line.slice(match[0].length) : line;
 | 
						|
    }).join("\n");
 | 
						|
    return corrected;
 | 
						|
  }
 | 
						|
  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/.pnpm/monkey-around@3.0.0/node_modules/monkey-around/dist/index.mjs
 | 
						|
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 inherited = obj[method], hadOwn = obj.hasOwnProperty(method), original = hadOwn ? inherited : function() {
 | 
						|
    return Object.getPrototypeOf(obj)[method].apply(this, arguments);
 | 
						|
  };
 | 
						|
  let current = createWrapper(original);
 | 
						|
  if (inherited)
 | 
						|
    Object.setPrototypeOf(current, inherited);
 | 
						|
  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, inherited || 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 isObsidianBuiltinMathWidget = Object.hasOwn(widget, "math") && Object.hasOwn(widget, "block") && "initDOM" in proto && "render" in proto && "setPos" in proto && "hookClickHandler" in proto && "addEditButton" in proto && "resizeWidget" in proto;
 | 
						|
  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);
 | 
						|
  }
 | 
						|
};
 | 
						|
 | 
						|
/* nosourcemap */ |