2025-02-26 19:55:41 +00:00
|
|
|
import {
|
|
|
|
|
App,
|
|
|
|
|
Editor,
|
|
|
|
|
EditorPosition,
|
|
|
|
|
EditorSuggest,
|
|
|
|
|
EditorSuggestContext,
|
|
|
|
|
EditorSuggestTriggerInfo,
|
|
|
|
|
Plugin,
|
|
|
|
|
PluginSettingTab,
|
|
|
|
|
Setting
|
|
|
|
|
} from 'obsidian';
|
2025-02-23 11:16:46 +00:00
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
interface MathTypePrefs {
|
|
|
|
|
customMappings: { [key: string]: string };
|
2025-03-02 12:27:53 +00:00
|
|
|
startKey: string
|
2025-02-23 11:16:46 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
const DEFUALT_PREFS: MathTypePrefs = {
|
|
|
|
|
customMappings: {
|
|
|
|
|
// Basic Operations
|
|
|
|
|
'fraction': '\\frac{numerator}{denominator}',
|
|
|
|
|
'sum': '\\sum_{i=1}^{n}',
|
|
|
|
|
'product': '\\prod_{i=1}^{n}',
|
|
|
|
|
'integral': '\\int_{a}^{b}',
|
|
|
|
|
'double integral': '\\iint_{D}',
|
|
|
|
|
'triple integral': '\\iiint_{V}',
|
|
|
|
|
'contour integral': '\\oint_{C}',
|
|
|
|
|
|
|
|
|
|
// Roots and Powers
|
|
|
|
|
'square root': '\\sqrt{x}',
|
|
|
|
|
'nth root': '\\sqrt[n]{x}',
|
|
|
|
|
'power': 'x^{n}',
|
|
|
|
|
'subscript': 'x_{i}',
|
2025-02-23 11:16:46 +00:00
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
// Limits and Infinity
|
|
|
|
|
'infinity': '\\infty',
|
|
|
|
|
'limit': '\\lim_{x \\to \\infty}',
|
|
|
|
|
'limit to zero': '\\lim_{x \\to 0}',
|
|
|
|
|
'limit from above': '\\lim_{x \\to a^+}',
|
|
|
|
|
'limit from below': '\\lim_{x \\to a^-}',
|
2025-02-23 11:16:46 +00:00
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
// Matrices and Arrays
|
|
|
|
|
'matrix': '\\begin{matrix} a & b \\\\ c & d \\end{matrix}',
|
|
|
|
|
'pmatrix': '\\begin{pmatrix} a & b \\\\ c & d \\end{pmatrix}',
|
|
|
|
|
'bmatrix': '\\begin{bmatrix} a & b \\\\ c & d \\end{bmatrix}',
|
|
|
|
|
'vmatrix': '\\begin{vmatrix} a & b \\\\ c & d \\end{vmatrix}',
|
2025-02-23 11:16:46 +00:00
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
// Greek Letters
|
|
|
|
|
'alpha': '\\alpha',
|
|
|
|
|
'beta': '\\beta',
|
|
|
|
|
'gamma': '\\gamma',
|
|
|
|
|
'delta': '\\Delta',
|
|
|
|
|
'theta': '\\theta',
|
|
|
|
|
'pi': '\\pi',
|
|
|
|
|
'sigma': '\\sigma',
|
|
|
|
|
'omega': '\\omega',
|
2025-02-23 11:16:46 +00:00
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
// Operators and Relations
|
|
|
|
|
'plus minus': '\\pm',
|
|
|
|
|
'minus plus': '\\mp',
|
|
|
|
|
'times': '\\times',
|
|
|
|
|
'div': '\\div',
|
|
|
|
|
'not equals': '\\neq',
|
|
|
|
|
'approximately': '\\approx',
|
|
|
|
|
'less or equal': '\\leq',
|
|
|
|
|
'greater or equal': '\\geq',
|
2025-02-23 11:16:46 +00:00
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
// Sets and Set Operations
|
|
|
|
|
'intersection': '\\cap',
|
|
|
|
|
'union': '\\cup',
|
|
|
|
|
'big intersection': '\\bigcap_{i=1}^n',
|
|
|
|
|
'big union': '\\bigcup_{i=1}^n',
|
|
|
|
|
'subset': '\\subset',
|
|
|
|
|
'proper subset': '\\subsetneq',
|
|
|
|
|
'superset': '\\supset',
|
|
|
|
|
'proper superset': '\\supsetneq',
|
|
|
|
|
'not subset': '\\not\\subset',
|
|
|
|
|
'element of': '\\in',
|
|
|
|
|
'not element of': '\\notin',
|
|
|
|
|
'empty set': '\\emptyset',
|
|
|
|
|
'null set': '\\varnothing',
|
|
|
|
|
'set minus': '\\setminus',
|
|
|
|
|
'power set': '\\mathcal{P}',
|
|
|
|
|
'natural numbers': '\\mathbb{N}',
|
|
|
|
|
'integers': '\\mathbb{Z}',
|
|
|
|
|
'rational numbers': '\\mathbb{Q}',
|
|
|
|
|
'real numbers': '\\mathbb{R}',
|
|
|
|
|
'complex numbers': '\\mathbb{C}',
|
|
|
|
|
'set brackets': '\\{x : x > 0\\}',
|
|
|
|
|
'cartesian product': '\\times',
|
|
|
|
|
'therefore': '\\therefore',
|
|
|
|
|
'because': '\\because',
|
|
|
|
|
|
|
|
|
|
// Calculus and Functions
|
|
|
|
|
'partial': '\\partial',
|
|
|
|
|
'nabla': '\\nabla',
|
|
|
|
|
'derivative': '\\frac{d}{dx}',
|
|
|
|
|
'partial derivative': '\\frac{\\partial}{\\partial x}',
|
|
|
|
|
'sine': '\\sin',
|
|
|
|
|
'cosine': '\\cos',
|
|
|
|
|
'tangent': '\\tan',
|
|
|
|
|
|
|
|
|
|
// Arrows and Accents
|
|
|
|
|
'rightarrow': '\\rightarrow',
|
|
|
|
|
'leftarrow': '\\leftarrow',
|
|
|
|
|
'leftrightarrow': '\\leftrightarrow',
|
|
|
|
|
'Rightarrow': '\\Rightarrow',
|
|
|
|
|
'Leftarrow': '\\Leftarrow',
|
|
|
|
|
'hat': '\\hat{x}',
|
|
|
|
|
'bar': '\\bar{x}',
|
|
|
|
|
'vec': '\\vec{x}',
|
|
|
|
|
|
|
|
|
|
// Spacing and Alignment
|
|
|
|
|
'quad space': '\\quad',
|
|
|
|
|
'text': '\\text{text here}',
|
|
|
|
|
'newline': '\\\\',
|
|
|
|
|
'horizontal space': '\\hspace{1cm}',
|
|
|
|
|
'vertical space': '\\vspace{1cm}',
|
2025-02-23 11:16:46 +00:00
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
// Probability and Statistics
|
|
|
|
|
'probability': '\\mathbb{P}(A)',
|
|
|
|
|
'conditional probability': '\\mathbb{P}(A|B)',
|
|
|
|
|
'expected value': '\\mathbb{E}[X]',
|
|
|
|
|
'variance': '\\text{Var}(X)',
|
|
|
|
|
'standard deviation': '\\sigma',
|
|
|
|
|
'normal distribution': '\\mathcal{N}(\\mu,\\sigma^2)',
|
|
|
|
|
'binomial distribution': '\\text{Bin}(n,p)',
|
|
|
|
|
'random variable': '\\mathcal{X}',
|
|
|
|
|
'independent': '\\perp',
|
|
|
|
|
'correlation': '\\rho',
|
|
|
|
|
'covariance': '\\text{Cov}(X,Y)',
|
|
|
|
|
'combination': '\\binom{n}{k}',
|
|
|
|
|
'permutation': 'P(n,k)',
|
|
|
|
|
'sample space': '\\Omega',
|
|
|
|
|
'independence': '\\perp\\!\\!\\perp',
|
|
|
|
|
'proportional to': '\\propto',
|
|
|
|
|
'chi-squared': '\\chi^2',
|
|
|
|
|
'beta distribution': '\\text{Beta}(\\alpha,\\beta)',
|
|
|
|
|
'gamma distribution': '\\text{Gamma}(k,\\theta)',
|
|
|
|
|
'poisson distribution': '\\text{Pois}(\\lambda)',
|
|
|
|
|
'uniform distribution': '\\text{Unif}(a,b)',
|
|
|
|
|
'exponential distribution': '\\text{Exp}(\\lambda)',
|
|
|
|
|
|
|
|
|
|
// Logic Symbols
|
|
|
|
|
'logical and': '\\land',
|
|
|
|
|
'logical or': '\\lor',
|
|
|
|
|
'logical not': '\\neg',
|
|
|
|
|
'implies': '\\implies',
|
|
|
|
|
'if and only if': '\\iff',
|
|
|
|
|
'forall': '\\forall',
|
|
|
|
|
'exists': '\\exists',
|
|
|
|
|
'not exists': '\\nexists',
|
|
|
|
|
'models': '\\models',
|
|
|
|
|
'proves': '\\vdash',
|
|
|
|
|
'contradiction': '\\bot',
|
|
|
|
|
'tautology': '\\top'
|
2025-03-02 12:27:53 +00:00
|
|
|
},
|
|
|
|
|
startKey: "^"
|
2025-02-26 19:55:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export default class MathType extends Plugin {
|
|
|
|
|
settings: MathTypePrefs;
|
|
|
|
|
|
|
|
|
|
async onload() {
|
|
|
|
|
await this.loadSettings();
|
2025-02-23 11:16:46 +00:00
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
// Register the suggester
|
|
|
|
|
this.registerEditorSuggest(new MathTypeSuggest(this));
|
|
|
|
|
|
|
|
|
|
// Add settings tab
|
|
|
|
|
this.addSettingTab(new PrefsTab(this.app, this));
|
|
|
|
|
}
|
2025-02-23 11:16:46 +00:00
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
getWordUnderCursor(line: string, cursorPos: number): string {
|
|
|
|
|
const words = line.slice(0, cursorPos).split(' ');
|
|
|
|
|
return words[words.length - 1].toLowerCase();
|
2025-02-23 11:16:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async loadSettings() {
|
2025-02-26 19:55:41 +00:00
|
|
|
this.settings = Object.assign({}, DEFUALT_PREFS, await this.loadData());
|
2025-02-23 11:16:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async saveSettings() {
|
|
|
|
|
await this.saveData(this.settings);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
// Suggest dropdown
|
|
|
|
|
class MathTypeSuggest extends EditorSuggest<string> {
|
|
|
|
|
plugin: MathType;
|
|
|
|
|
|
|
|
|
|
constructor(plugin: MathType) {
|
|
|
|
|
super(plugin.app);
|
|
|
|
|
this.plugin = plugin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onTrigger(cursor: EditorPosition, editor: Editor): EditorSuggestTriggerInfo | null {
|
|
|
|
|
const line = editor.getLine(cursor.line);
|
|
|
|
|
const word = this.plugin.getWordUnderCursor(line, cursor.ch);
|
|
|
|
|
|
2025-03-02 12:27:53 +00:00
|
|
|
|
|
|
|
|
if (!word.startsWith((this.plugin.settings.startKey))) return null;
|
|
|
|
|
|
|
|
|
|
const lookup = word.substring(1)
|
|
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
// Check if the word matches any of our mappings
|
|
|
|
|
const hasMatch = Object.keys(this.plugin.settings.customMappings)
|
2025-03-02 12:27:53 +00:00
|
|
|
.some(key => key.includes(lookup) && lookup.length >= 2); // Only trigger for 2+ characters
|
2025-02-26 19:55:41 +00:00
|
|
|
|
|
|
|
|
if (hasMatch) {
|
|
|
|
|
return {
|
|
|
|
|
start: {
|
|
|
|
|
line: cursor.line,
|
|
|
|
|
ch: cursor.ch - word.length
|
|
|
|
|
},
|
|
|
|
|
end: cursor,
|
2025-03-02 12:27:53 +00:00
|
|
|
query: lookup
|
2025-02-26 19:55:41 +00:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
getSuggestions(context: EditorSuggestContext): string[] {
|
|
|
|
|
const word = this.plugin.getWordUnderCursor(context.query, context.query.length);
|
|
|
|
|
return Object.entries(this.plugin.settings.customMappings)
|
|
|
|
|
.filter(([key]) => key.includes(word))
|
|
|
|
|
.map(([_, value]) => value);
|
2025-02-23 11:16:46 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
renderSuggestion(value: string, el: HTMLElement): void {
|
|
|
|
|
const suggestionEl = el.createDiv({cls: "suggestion-item"});
|
|
|
|
|
suggestionEl.createSpan({
|
|
|
|
|
text: value,
|
|
|
|
|
cls: "suggestion-content"
|
|
|
|
|
});
|
2025-02-23 11:16:46 +00:00
|
|
|
}
|
|
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
selectSuggestion(value: string, evt: MouseEvent | KeyboardEvent): void {
|
|
|
|
|
if (!this.context) return;
|
|
|
|
|
|
|
|
|
|
const editor = this.context.editor;
|
|
|
|
|
|
|
|
|
|
editor.replaceRange(
|
|
|
|
|
`$${value}$`,
|
|
|
|
|
this.context.start,
|
|
|
|
|
this.context.end
|
|
|
|
|
);
|
2025-02-23 11:16:46 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
// Prefs tab
|
|
|
|
|
class PrefsTab extends PluginSettingTab {
|
|
|
|
|
plugin: MathType;
|
2025-02-23 11:16:46 +00:00
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
constructor(app: App, plugin: MathType) {
|
2025-02-23 11:16:46 +00:00
|
|
|
super(app, plugin);
|
|
|
|
|
this.plugin = plugin;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
display(): void {
|
|
|
|
|
const {containerEl} = this;
|
|
|
|
|
|
|
|
|
|
containerEl.empty();
|
|
|
|
|
|
2025-02-26 19:55:41 +00:00
|
|
|
containerEl.createEl('h2', {text: 'MathType Suggester Prefs'});
|
2025-03-02 12:27:53 +00:00
|
|
|
|
|
|
|
|
new Setting(containerEl)
|
|
|
|
|
.setName('Start Key')
|
|
|
|
|
.setDesc('Set the key to trigger MathType suggestions.')
|
|
|
|
|
.addText(text => text
|
|
|
|
|
.setValue(this.plugin.settings.startKey || '')
|
|
|
|
|
.onChange(async (newValue) => {
|
|
|
|
|
this.plugin.settings.startKey = newValue;
|
|
|
|
|
await this.plugin.saveSettings();
|
|
|
|
|
}));
|
|
|
|
|
|
2025-02-23 11:16:46 +00:00
|
|
|
}
|
|
|
|
|
}
|