1967 lines
115 KiB
JavaScript
1967 lines
115 KiB
JavaScript
/*
|
|
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
|
|
if you want to view the source visit the plugins github repository
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
var obsidian = require('obsidian');
|
|
var state = require('@codemirror/state');
|
|
var view = require('@codemirror/view');
|
|
|
|
/*! *****************************************************************************
|
|
Copyright (c) Microsoft Corporation.
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
PERFORMANCE OF THIS SOFTWARE.
|
|
***************************************************************************** */
|
|
|
|
function __awaiter(thisArg, _arguments, P, generator) {
|
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
});
|
|
}
|
|
|
|
const DEFAULT_SETTINGS = {
|
|
useMathKeyboardShortcut_toggle: false,
|
|
moveIntoMath_toggle: true,
|
|
autoCloseMath_toggle: true,
|
|
autoCloseRound_toggle: true,
|
|
autoCloseSquare_toggle: true,
|
|
autoCloseCurly_toggle: true,
|
|
addAlignBlock_toggle: true,
|
|
addAlignBlock_parameter: "align*",
|
|
autoAlignSymbols: "= > < \\le \\ge \\neq \\approx",
|
|
addCasesBlock_toggle: true,
|
|
shiftEnter_toggle: false,
|
|
addMatrixBlock_toggle: true,
|
|
addMatrixBlock_parameter: "pmatrix",
|
|
autoFraction_toggle: true,
|
|
autoLargeBracket_toggle: true,
|
|
autoSumLimit_toggle: true,
|
|
autoEncloseSup_toggle: true,
|
|
autoEncloseSub_toggle: true,
|
|
encloseSelection_toggle: true,
|
|
autoGreekCommandMathMode_toggle: true,
|
|
customShorthand_toggle: true,
|
|
useTabtoComplete_toggle: false,
|
|
customShorthand_parameter: "bi:::\\binom{#cursor}{#tab};\nsq:::\\sqrt{};\nbb:::\\mathbb{};\nbf:::\\mathbf{};\nte:::\\text{};\ninf:::\\infty;\n" +
|
|
"cd:::\\cdot;\nqu:::\\quad;\nti:::\\times;\n" +
|
|
"al:::\\alpha;\nbe:::\\beta;\nga:::\\gamma;\nGa:::\\Gamma;\n" +
|
|
"de:::\\delta;\nDe:::\\Delta;\nep:::\\epsilon;\nze:::\\zeta;\n" +
|
|
"et:::\\eta;\nth:::\\theta;\nTh:::\\Theta;\nio:::\\iota;\n" +
|
|
"ka:::\\kappa;\nla:::\\lambda;\nLa:::\\Lambda;\nmu:::\\mu;\n" +
|
|
"nu:::\\nu;\nxi:::\\xi;\nXi:::\\Xi;\npi:::\\pi;\nPi:::\\Pi;\n" +
|
|
"rh:::\\rho;\nsi:::\\sigma;\nSi:::\\Sigma;\nta:::\\tau;\n" +
|
|
"up:::\\upsilon;\nUp:::\\Upsilon;\nph:::\\phi;\nPh:::\\Phi;\nch:::\\chi;\n" +
|
|
"ps:::\\psi;\nPs:::\\Psi;\nom:::\\omega;\nOm:::\\Omega"
|
|
};
|
|
class QuickLatexPlugin extends obsidian.Plugin {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.vimAllow_autoCloseMath = true;
|
|
this.makeExtensionThing = () => state.Prec.high(view.keymap.of([
|
|
{
|
|
key: '$',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (editor.getSelection().length > 0) {
|
|
// enclose selected text
|
|
if (this.settings.encloseSelection_toggle) {
|
|
const anchor = editor.getCursor("anchor");
|
|
const head = editor.getCursor("head");
|
|
editor.replaceSelection(`$${editor.getSelection()}$`);
|
|
if (anchor.line > head.line) {
|
|
editor.setSelection({ line: anchor.line, ch: anchor.ch }, { line: head.line, ch: head.ch + 1 });
|
|
}
|
|
else if (anchor.line < head.line) {
|
|
editor.setSelection({ line: anchor.line, ch: anchor.ch + 1 }, { line: head.line, ch: head.ch });
|
|
}
|
|
else {
|
|
editor.setSelection({ line: anchor.line, ch: anchor.ch + 1 }, { line: head.line, ch: head.ch + 1 });
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
else {
|
|
// close math symbol
|
|
const position = editor.getCursor();
|
|
const prev_char = editor.getRange({ line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
const next_char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 1 });
|
|
const next2_char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 2 });
|
|
if (prev_char != "$" && next_char == "$") {
|
|
if (next2_char == "$$") {
|
|
editor.setCursor({ line: position.line, ch: position.ch + 2 });
|
|
return true;
|
|
}
|
|
else {
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
return true;
|
|
}
|
|
}
|
|
// auto close math
|
|
if (this.settings.autoCloseMath_toggle && this.vimAllow_autoCloseMath) {
|
|
const prev_char = editor.getRange({ line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
const line = editor.getLine(position.line);
|
|
const count = (line.match(/\$/g) || []).length;
|
|
if (prev_char != "\\" && count % 2 == 0) {
|
|
editor.replaceSelection("$");
|
|
}
|
|
}
|
|
// move into math
|
|
if (this.settings.moveIntoMath_toggle) {
|
|
const position = editor.getCursor();
|
|
const t = editor.getRange({ line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
const t2 = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 1 });
|
|
const t_2 = editor.getRange({ line: position.line, ch: position.ch - 2 }, { line: position.line, ch: position.ch });
|
|
if (t == '$' && t2 != '$') {
|
|
editor.setCursor({ line: position.line, ch: position.ch - 1 });
|
|
}
|
|
else if (t_2 == '$$') {
|
|
editor.setCursor({ line: position.line, ch: position.ch - 1 });
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
},
|
|
},
|
|
// delete pair of math symbols with backspace
|
|
{ key: 'Backspace',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
const position = editor.getCursor();
|
|
const prev_char = editor.getRange({ line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
const next_char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 1 });
|
|
if (prev_char == "$" && next_char == "$") {
|
|
editor.replaceRange("", { line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch + 1 });
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
},
|
|
{
|
|
key: 'Tab',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (this.withinMath(editor)) {
|
|
const position = editor.getCursor();
|
|
const current_line = editor.getLine(position.line);
|
|
const end_pos = editor.getLine(position.line).length;
|
|
const next_line = editor.getLine(position.line + 1);
|
|
// check for custom shorthand
|
|
if (this.settings.customShorthand_toggle && !this.withinText(editor, position.ch)) {
|
|
if (this.settings.useTabtoComplete_toggle) {
|
|
if (this.customShorthand(editor, position)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
// Tab to go to next #tab with numbering or without numbering if there are no #tabs with numbers
|
|
const indexed_tab_expr = /#tab(\d+)?/g;
|
|
let next_match;
|
|
let current_match;
|
|
while ((current_match = indexed_tab_expr.exec(current_line)) != null) {
|
|
if (!next_match || parseInt(current_match[1]) < parseInt(next_match[1]))
|
|
next_match = current_match;
|
|
}
|
|
if (next_match) {
|
|
const tab_position = next_match.index;
|
|
editor.replaceRange("", { line: position.line, ch: tab_position }, { line: position.line, ch: tab_position + next_match[0].length });
|
|
editor.setCursor({ line: position.line, ch: tab_position });
|
|
return true;
|
|
}
|
|
// Tab shortcut for matrix block
|
|
if (this.settings.addMatrixBlock_toggle) {
|
|
const begin_matrix = ['\\begin{' + this.settings.addMatrixBlock_parameter + '}', "\\begin{matrix}", "\\begin{bmatrix}", "\\begin{Bmatrix}", "\\begin{vmatrix}", "\\begin{Vmatrix}", "\\begin{smallmatrix}"];
|
|
const end_matrix = ['\\end{' + this.settings.addMatrixBlock_parameter + '}', "\\end{matrix}", "\\end{bmatrix}", "\\end{Bmatrix}", "\\end{vmatrix}", "\\end{Vmatrix}", "\\end{smallmatrix}"];
|
|
let state = false;
|
|
let end_text = "";
|
|
for (let i = 0; i < begin_matrix.length; i++) {
|
|
if (this.withinAnyBrackets_document(editor, begin_matrix[i], end_matrix[i])) {
|
|
state = true;
|
|
end_text = end_matrix[i];
|
|
break;
|
|
}
|
|
}
|
|
const position = editor.getCursor();
|
|
const prev3_char = editor.getRange({ line: position.line, ch: position.ch - 3 }, { line: position.line, ch: position.ch });
|
|
if (state) {
|
|
if (prev3_char == ' & ') {
|
|
editor.replaceRange('', { line: position.line, ch: position.ch - 3 }, { line: position.line, ch: position.ch });
|
|
editor.setCursor({ line: position.line, ch: position.ch + end_text.length - 3 });
|
|
return true;
|
|
}
|
|
else {
|
|
editor.replaceSelection(' & ');
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
// Tab shortcut for cases block
|
|
if (this.settings.addCasesBlock_toggle) {
|
|
if (this.withinAnyBrackets_document(editor, '\\begin{cases}', '\\end{cases}')) {
|
|
const position = editor.getCursor();
|
|
const prev3_char = editor.getRange({ line: position.line, ch: position.ch - 3 }, { line: position.line, ch: position.ch });
|
|
const next_line = editor.getLine(position.line + 1);
|
|
if (prev3_char == ' & ' && next_line == '\\end{cases}') {
|
|
editor.replaceRange('', { line: position.line, ch: position.ch - 3 }, { line: position.line, ch: position.ch });
|
|
editor.setCursor({ line: position.line + 1, ch: next_line.length });
|
|
return true;
|
|
}
|
|
else {
|
|
editor.replaceSelection(' & ');
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
// Tab out of $
|
|
const next_2 = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 2 });
|
|
if (next_2 == "$$") {
|
|
editor.setCursor({ line: position.line, ch: position.ch + 2 });
|
|
return true;
|
|
}
|
|
else if (position.ch == end_pos && next_line == "$$") {
|
|
editor.setCursor({ line: position.line + 1, ch: next_line.length });
|
|
return true;
|
|
}
|
|
else if (next_2[0] == "$") {
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
return true;
|
|
}
|
|
// Tab to next close bracket
|
|
const following_text = editor.getRange({ line: position.line, ch: position.ch + 1 }, { line: position.line, ch: current_line.length });
|
|
const close_symbols = ['}', ']', ')', '$'];
|
|
for (let i = 0; i < following_text.length; i++) {
|
|
if (close_symbols.contains(following_text[i])) {
|
|
editor.setCursor({ line: position.line, ch: position.ch + i + 1 });
|
|
return true;
|
|
}
|
|
}
|
|
// Tab out of align block
|
|
if (position.ch == end_pos && next_line == '\\end{' + this.settings.addAlignBlock_parameter + '}') {
|
|
editor.setCursor({ line: position.line + 1, ch: next_line.length });
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
key: 'Shift-Tab',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (this.withinMath(editor)) {
|
|
const position = editor.getCursor();
|
|
const preceding_text = editor.getRange({ line: position.line, ch: 0 }, { line: position.line, ch: position.ch });
|
|
const close_symbols = ['}', ']', ')'];
|
|
for (let i = preceding_text.length; i >= 0; i--) {
|
|
if (close_symbols.contains(preceding_text[i])) {
|
|
editor.setCursor({ line: position.line, ch: i });
|
|
return true;
|
|
}
|
|
else if (position.ch - i > 1 && preceding_text[i] == "$") {
|
|
editor.setCursor({ line: position.line, ch: i + 1 });
|
|
return true;
|
|
}
|
|
else if (preceding_text.slice(-2) == "$$") {
|
|
editor.setCursor({ line: position.line, ch: position.ch - 2 });
|
|
return true;
|
|
}
|
|
else if (preceding_text[-1] == "$") {
|
|
editor.setCursor({ line: position.line, ch: position.ch - 1 });
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
key: 'Space',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (!this.settings.autoFraction_toggle &&
|
|
!this.settings.autoLargeBracket_toggle &&
|
|
!this.settings.autoEncloseSup_toggle &&
|
|
!this.settings.autoEncloseSub_toggle &&
|
|
!this.settings.customShorthand_toggle)
|
|
return false;
|
|
if (this.withinMath(editor)) {
|
|
const position = editor.getCursor();
|
|
const current_line = editor.getLine(position.line);
|
|
const last_dollar = current_line.lastIndexOf('$', position.ch - 1);
|
|
// check for custom shorthand
|
|
if (this.settings.customShorthand_toggle && !this.withinText(editor, position.ch)) {
|
|
if (!this.settings.useTabtoComplete_toggle) {
|
|
if (this.customShorthand(editor, position)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
// find last unbracketed subscript within last 10 characters and perform autoEncloseSub
|
|
// ignore expression that contain + - * / ^
|
|
const last_math = current_line.lastIndexOf('$', position.ch - 1);
|
|
if (this.settings.autoEncloseSub_toggle) {
|
|
let last_subscript = current_line.lastIndexOf('_', position.ch);
|
|
if (last_subscript != -1 && last_subscript > last_math) {
|
|
const letter_after_subscript = editor.getRange({ line: position.line, ch: last_subscript + 1 }, { line: position.line, ch: last_subscript + 2 });
|
|
if (letter_after_subscript != "{" &&
|
|
(position.ch - last_subscript) <= 10) {
|
|
editor.replaceSelection("}");
|
|
editor.replaceRange("{", { line: position.line, ch: last_subscript + 1 });
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
// retrieve the last unbracketed superscript
|
|
let last_superscript = current_line.lastIndexOf('^', position.ch);
|
|
while (last_superscript != -1) {
|
|
const two_letters_after_superscript = editor.getRange({ line: position.line, ch: last_superscript + 1 }, { line: position.line, ch: last_superscript + 3 });
|
|
if (two_letters_after_superscript[0] == '{' || two_letters_after_superscript == ' {') {
|
|
last_superscript = current_line.lastIndexOf('^', last_superscript - 1);
|
|
}
|
|
else if (last_superscript < last_math) {
|
|
last_superscript = -1;
|
|
break;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
// retrieve the last divide symbol
|
|
let last_divide = current_line.lastIndexOf('/', position.ch - 2);
|
|
while (last_divide != -1) {
|
|
const around_divide = editor.getRange({ line: position.line, ch: last_divide - 1 }, { line: position.line, ch: last_divide + 2 });
|
|
if (around_divide[0] == ' ' && around_divide[2] == ' ') {
|
|
last_divide = current_line.lastIndexOf('^', last_divide - 1);
|
|
}
|
|
else if (last_divide < last_math) {
|
|
last_divide = -1;
|
|
break;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
// perform autoEncloseSup
|
|
if (this.settings.autoEncloseSup_toggle) {
|
|
if (last_superscript > last_divide) {
|
|
// if any brackets from last sup to cursor still unclosed, dont do autoEncloseSup yet
|
|
const brackets = [['(', ')'], ['{', '}'], ['[', ']']];
|
|
if (!brackets.some(e => this.unclosed_bracket(editor, e[0], e[1], position.ch, last_superscript)[0])) {
|
|
return this.autoEncloseSup(editor, event, last_superscript);
|
|
}
|
|
}
|
|
}
|
|
// perform autoFraction
|
|
if (this.settings.autoFraction_toggle && !this.withinText(editor, last_divide)) {
|
|
if (last_divide > last_dollar) {
|
|
const brackets = [['(', ')'], ['{', '}'], ['[', ']']];
|
|
// if any brackets in denominator still unclosed, dont do autoFraction yet
|
|
if (!brackets.some(e => this.unclosed_bracket(editor, e[0], e[1], position.ch, last_divide)[0])) {
|
|
return this.autoFractionCM6(editor, last_superscript);
|
|
}
|
|
}
|
|
}
|
|
// perform autoLargeBracket
|
|
if (this.settings.autoLargeBracket_toggle) {
|
|
let symbol_before = editor.getRange({ line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
if (symbol_before == ')' || symbol_before == ']') {
|
|
return this.autoLargeBracket(editor, event);
|
|
}
|
|
}
|
|
// perform autoAlign
|
|
if (this.autoAlign_array.length) {
|
|
if (this.withinAnyBrackets_document(editor, '\\begin{' + this.settings.addAlignBlock_parameter, '\\end{' + this.settings.addAlignBlock_parameter)) {
|
|
let keyword = "";
|
|
let keyword_length = 0;
|
|
for (let i = 0; i < this.autoAlign_array.length; i++) {
|
|
keyword_length = this.autoAlign_array[i].length;
|
|
if (keyword_length > position.ch) {
|
|
continue;
|
|
}
|
|
else {
|
|
keyword = editor.getRange({ line: position.line, ch: position.ch - keyword_length }, { line: position.line, ch: position.ch });
|
|
}
|
|
if (keyword == this.autoAlign_array[i]) {
|
|
editor.replaceRange('&', { line: position.line, ch: position.ch - keyword_length });
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (this.settings.autoGreekCommandMathMode_toggle) {
|
|
const greekSymbols = ['alpha', 'Alpha', 'beta', 'gamma', 'Gamma', 'delta', 'Delta', 'epsilon', 'zeta', 'eta', 'theta', 'Theta', 'iota', 'kappa', 'lambda', 'Lambda', 'mu', 'nu', 'xi', 'Xi', 'omicron', 'pi', 'Pi', 'rho', 'sigma', 'Sigma', 'tau', 'upsilon', 'Upsilon', 'phi', 'Phi', 'chi', 'psi', 'Psi', 'omega', 'Omega', 'varepsilon', 'vartheta', 'varrho', 'varphi'];
|
|
const greekSymbolsSlashed = greekSymbols.map(x => '\\' + x);
|
|
const position = editor.getCursor();
|
|
const current_line = editor.getLine(position.line);
|
|
const last_slash = current_line.lastIndexOf('\\', position.ch - 1);
|
|
if (last_slash != -1) {
|
|
const entered = current_line.substring(last_slash, position.ch);
|
|
if (greekSymbolsSlashed.contains(entered))
|
|
editor.replaceRange('$' + entered + '$', { line: position.line, ch: position.ch - entered.length }, { line: position.line, ch: position.ch });
|
|
}
|
|
}
|
|
},
|
|
},
|
|
{
|
|
key: 'Shift-Space',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (!this.settings.customShorthand_toggle)
|
|
return false;
|
|
if (this.withinMath(editor)) {
|
|
const position = editor.getCursor();
|
|
// check for custom shorthand
|
|
if (this.settings.customShorthand_toggle && !this.withinText(editor, position.ch)) {
|
|
let keyword = "";
|
|
let keyword_length = 0;
|
|
for (let i = 0; i < this.shorthand_array.length; i++) {
|
|
keyword_length = this.shorthand_array[i][0].length;
|
|
if (keyword_length > position.ch) {
|
|
continue;
|
|
}
|
|
else if (keyword_length == position.ch) {
|
|
keyword = "@" + editor.getRange({ line: position.line, ch: position.ch - keyword_length }, { line: position.line, ch: position.ch });
|
|
}
|
|
else {
|
|
keyword = editor.getRange({ line: position.line, ch: position.ch - keyword_length - 1 }, { line: position.line, ch: position.ch });
|
|
}
|
|
if (keyword[0].toLowerCase() == keyword[0].toUpperCase() ||
|
|
keyword[0] == "@") {
|
|
if (this.shorthand_array[i][0] == keyword.slice(-keyword_length) &&
|
|
this.shorthand_array[i][1] != keyword) {
|
|
const replace_slash = (keyword[0] == "\\" && this.shorthand_array[i][1][0] == "\\") ? 1 : 0;
|
|
const set_cursor_position = this.shorthand_array[i][1].indexOf("#cursor");
|
|
editor.replaceRange(this.shorthand_array[i][1], { line: position.line, ch: position.ch - keyword_length - replace_slash }, { line: position.line, ch: position.ch });
|
|
if (set_cursor_position != -1) {
|
|
editor.replaceRange("", { line: position.line, ch: position.ch - keyword_length - replace_slash + set_cursor_position }, { line: position.line, ch: position.ch - keyword_length - replace_slash + set_cursor_position + 7 });
|
|
editor.setCursor({ line: position.line, ch: position.ch - keyword_length - replace_slash + set_cursor_position });
|
|
}
|
|
else if (this.shorthand_array[i][1].slice(-2) == "{}") {
|
|
editor.setCursor({ line: position.line,
|
|
ch: position.ch + this.shorthand_array[i][1].length - keyword_length - 1 - replace_slash });
|
|
}
|
|
else ;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
key: 'Enter',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (this.settings.addAlignBlock_toggle && this.settings.shiftEnter_toggle == false) {
|
|
if (this.withinAnyBrackets_document(editor, '\\begin{' + this.settings.addAlignBlock_parameter, '\\end{' + this.settings.addAlignBlock_parameter)) {
|
|
editor.replaceSelection('\\\\\n');
|
|
return true;
|
|
}
|
|
}
|
|
if (this.settings.addCasesBlock_toggle && this.settings.shiftEnter_toggle == false) {
|
|
if (this.withinAnyBrackets_document(editor, '\\begin{cases}', '\\end{cases}')) {
|
|
editor.replaceSelection(' \\\\\n');
|
|
return true;
|
|
}
|
|
}
|
|
if (this.settings.addMatrixBlock_toggle) {
|
|
const begin_matrix = ['\\begin{' + this.settings.addMatrixBlock_parameter + '}', "\\begin{matrix}", "\\begin{bmatrix}", "\\begin{Bmatrix}", "\\begin{vmatrix}", "\\begin{Vmatrix}", "\\begin{smallmatrix}"];
|
|
const end_matrix = ['\\end{' + this.settings.addMatrixBlock_parameter + '}', "\\end{matrix}", "\\end{bmatrix}", "\\end{Bmatrix}", "\\end{vmatrix}", "\\end{Vmatrix}", "\\end{smallmatrix}"];
|
|
let state = false;
|
|
for (let i = 0; i < begin_matrix.length; i++) {
|
|
if (this.withinAnyBrackets_document(editor, begin_matrix[i], end_matrix[i])) {
|
|
state = true;
|
|
break;
|
|
}
|
|
}
|
|
if (state) {
|
|
editor.replaceSelection(' \\\\ ');
|
|
return true;
|
|
}
|
|
}
|
|
// double enter for $$
|
|
if (this.withinMath(editor)) {
|
|
const position = editor.getCursor();
|
|
const prev2_Char = editor.getRange({ line: position.line, ch: position.ch - 2 }, { line: position.line, ch: position.ch });
|
|
const next2_Char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 2 });
|
|
if (prev2_Char == "$$" && next2_Char == "$$") {
|
|
editor.replaceSelection('\n');
|
|
editor.setCursor(position);
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
key: 'Shift-Enter',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (this.settings.addAlignBlock_toggle && this.settings.shiftEnter_toggle == true) {
|
|
if (this.withinAnyBrackets_document(editor, '\\begin{' + this.settings.addAlignBlock_parameter, '\\end{' + this.settings.addAlignBlock_parameter)) {
|
|
editor.replaceSelection('\\\\\n');
|
|
return true;
|
|
}
|
|
}
|
|
if (this.settings.addCasesBlock_toggle && this.settings.shiftEnter_toggle == true) {
|
|
if (this.withinAnyBrackets_document(editor, '\\begin{cases}', '\\end{cases}')) {
|
|
editor.replaceSelection(' \\\\\n');
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
},
|
|
{
|
|
key: '{',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (this.withinMath(editor)) {
|
|
if (this.settings.autoCloseCurly_toggle) {
|
|
if (editor.getSelection().length > 0) {
|
|
return false;
|
|
}
|
|
const position = editor.getCursor();
|
|
const brackets = [['(', ')'], ['{', '}'], ['[', ']']];
|
|
const next_char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 1 });
|
|
const next_2char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 2 });
|
|
const followed_by_$spacetabnonedoubleslash = (['$', ' ', ' ', ''].contains(next_char) || next_2char == '\\\\');
|
|
if (!this.withinAnyBrackets_inline(editor, brackets) && followed_by_$spacetabnonedoubleslash) {
|
|
editor.replaceSelection('{}');
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
key: '[',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (this.withinMath(editor)) {
|
|
if (this.settings.autoCloseSquare_toggle) {
|
|
if (editor.getSelection().length > 0) {
|
|
return false;
|
|
}
|
|
const position = editor.getCursor();
|
|
const brackets = [['(', ')'], ['{', '}'], ['[', ']']];
|
|
const next_char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 1 });
|
|
const next_2char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 2 });
|
|
const followed_by_$spacetabnonedoubleslash = (['$', ' ', ' ', ''].contains(next_char) || next_2char == '\\\\');
|
|
if (!this.withinAnyBrackets_inline(editor, brackets) && followed_by_$spacetabnonedoubleslash) {
|
|
editor.replaceSelection('[]');
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
key: '(',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (this.withinMath(editor)) {
|
|
if (this.settings.autoCloseRound_toggle) {
|
|
if (editor.getSelection().length > 0) {
|
|
return false;
|
|
}
|
|
const position = editor.getCursor();
|
|
const brackets = [['(', ')'], ['{', '}'], ['[', ']']];
|
|
const next_char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 1 });
|
|
const next_2char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 2 });
|
|
const followed_by_$spacetabnonedoubleslash = (['$', ' ', ' ', ''].contains(next_char) || next_2char == '\\\\');
|
|
if (!this.withinAnyBrackets_inline(editor, brackets) && followed_by_$spacetabnonedoubleslash) {
|
|
editor.replaceSelection('()');
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
key: '}',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (this.withinMath(editor)) {
|
|
if (this.settings.autoCloseCurly_toggle) {
|
|
const position = editor.getCursor();
|
|
const end = editor.getLine(position.line).length;
|
|
const next_sym = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 1 });
|
|
if (!this.unclosed_bracket(editor, "{", "}", end, 0)[0] &&
|
|
!this.unclosed_bracket(editor, "{", "}", end, 0, false)[0] &&
|
|
next_sym == "}") {
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
key: ']',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (this.withinMath(editor)) {
|
|
if (this.settings.autoCloseSquare_toggle) {
|
|
const position = editor.getCursor();
|
|
const end = editor.getLine(position.line).length;
|
|
const next_sym = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 1 });
|
|
if (!this.unclosed_bracket(editor, "[", "]", end, 0)[0] &&
|
|
!this.unclosed_bracket(editor, "[", "]", end, 0, false)[0] &&
|
|
next_sym == "]") {
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
key: ')',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (this.withinMath(editor)) {
|
|
if (this.settings.autoCloseRound_toggle) {
|
|
const position = editor.getCursor();
|
|
const end = editor.getLine(position.line).length;
|
|
const next_sym = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 1 });
|
|
if (!this.unclosed_bracket(editor, "(", ")", end, 0)[0] &&
|
|
!this.unclosed_bracket(editor, "(", ")", end, 0, false)[0] &&
|
|
next_sym == ")") {
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
return true;
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
{
|
|
key: 'm',
|
|
run: () => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
const editor = view.editor;
|
|
if (!this.withinMath(editor))
|
|
return false;
|
|
const position = editor.getCursor();
|
|
if (!this.settings.autoSumLimit_toggle)
|
|
return;
|
|
if (this.withinMath(editor)) {
|
|
if (editor.getRange({ line: position.line, ch: position.ch - 3 }, { line: position.line, ch: position.ch }) == '\\su') {
|
|
editor.replaceSelection('m\\limits');
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
},
|
|
},
|
|
]));
|
|
this.handleVimModeChange = (modeObj) => {
|
|
if (!modeObj || modeObj.mode === 'insert')
|
|
this.vimAllow_autoCloseMath = true;
|
|
else
|
|
this.vimAllow_autoCloseMath = false;
|
|
};
|
|
this.handleKeyDown = (cm, event) => {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return;
|
|
const editor = view.editor;
|
|
if (['$', ' ', 'Enter', 'Tab'].contains(event.key)) {
|
|
switch (event.key) {
|
|
case '$':
|
|
if (editor.getSelection().length > 0) {
|
|
if (this.settings.encloseSelection_toggle) {
|
|
const anchor = editor.getCursor("anchor");
|
|
const head = editor.getCursor("head");
|
|
editor.replaceSelection('$' + editor.getSelection() + '$');
|
|
if (anchor.line > head.line) {
|
|
editor.setSelection({ line: anchor.line, ch: anchor.ch }, { line: head.line, ch: head.ch + 1 });
|
|
}
|
|
else if (anchor.line < head.line) {
|
|
editor.setSelection({ line: anchor.line, ch: anchor.ch + 1 }, { line: head.line, ch: head.ch });
|
|
}
|
|
else {
|
|
editor.setSelection({ line: anchor.line, ch: anchor.ch + 1 }, { line: head.line, ch: head.ch + 1 });
|
|
}
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
// close math symbol
|
|
const position = editor.getCursor();
|
|
const prev_char = editor.getRange({ line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
const next_char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 1 });
|
|
const next2_char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 2 });
|
|
if (prev_char != "$" && next_char == "$") {
|
|
if (next2_char == "$$") {
|
|
editor.setCursor({ line: position.line, ch: position.ch + 2 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
else {
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
// perform autoCloseMath
|
|
if (this.settings.autoCloseMath_toggle && this.vimAllow_autoCloseMath) {
|
|
editor.replaceSelection("$");
|
|
}
|
|
// perform moveIntoMath
|
|
if (this.settings.moveIntoMath_toggle) {
|
|
const position = editor.getCursor();
|
|
const t = editor.getRange({ line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
const t2 = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 1 });
|
|
const t_2 = editor.getRange({ line: position.line, ch: position.ch - 2 }, { line: position.line, ch: position.ch });
|
|
if (t == '$' && t2 != '$') {
|
|
editor.setCursor({ line: position.line, ch: position.ch - 1 });
|
|
}
|
|
else if (t_2 == '$$') {
|
|
editor.setCursor({ line: position.line, ch: position.ch - 1 });
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
case ' ':
|
|
if (!this.settings.autoFraction_toggle &&
|
|
!this.settings.autoLargeBracket_toggle &&
|
|
!this.settings.autoEncloseSup_toggle &&
|
|
!this.settings.autoEncloseSub_toggle &&
|
|
!this.settings.customShorthand_toggle)
|
|
return;
|
|
if (this.withinMath(editor)) {
|
|
const position = editor.getCursor();
|
|
const current_line = editor.getLine(position.line);
|
|
const last_dollar = current_line.lastIndexOf('$', position.ch - 1);
|
|
// check for custom shorthand
|
|
if (this.settings.customShorthand_toggle && !this.withinText(editor, position.ch)) {
|
|
let keyword = "";
|
|
let keyword_length = 0;
|
|
for (let i = 0; i < this.shorthand_array.length; i++) {
|
|
keyword_length = this.shorthand_array[i][0].length;
|
|
if (keyword_length > position.ch) {
|
|
continue;
|
|
}
|
|
else if (keyword_length == position.ch) {
|
|
keyword = "@" + editor.getRange({ line: position.line, ch: position.ch - keyword_length }, { line: position.line, ch: position.ch });
|
|
}
|
|
else {
|
|
keyword = editor.getRange({ line: position.line, ch: position.ch - keyword_length - 1 }, { line: position.line, ch: position.ch });
|
|
}
|
|
if (keyword[0].toLowerCase() == keyword[0].toUpperCase() ||
|
|
keyword[0] == "@") {
|
|
if (this.shorthand_array[i][0] == keyword.slice(-keyword_length) &&
|
|
this.shorthand_array[i][1] != keyword) {
|
|
const replace_slash = (keyword[0] == "\\" && this.shorthand_array[i][1][0] == "\\") ? 1 : 0;
|
|
const set_cursor_position = this.shorthand_array[i][1].indexOf("#cursor");
|
|
editor.replaceRange(this.shorthand_array[i][1], { line: position.line, ch: position.ch - keyword_length - replace_slash }, { line: position.line, ch: position.ch });
|
|
if (set_cursor_position != -1) {
|
|
editor.replaceRange("", { line: position.line, ch: position.ch - keyword_length - replace_slash + set_cursor_position }, { line: position.line, ch: position.ch - keyword_length - replace_slash + set_cursor_position + 7 });
|
|
editor.setCursor({ line: position.line, ch: position.ch - keyword_length - replace_slash + set_cursor_position });
|
|
}
|
|
else if (this.shorthand_array[i][1].slice(-2) == "{}") {
|
|
editor.setCursor({ line: position.line,
|
|
ch: position.ch + this.shorthand_array[i][1].length - keyword_length - 1 - replace_slash });
|
|
}
|
|
else ;
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// find last unbracketed subscript within last 10 characters and perform autoEncloseSub
|
|
// ignore expression that contain + - * / ^
|
|
const last_math = current_line.lastIndexOf('$', position.ch - 1);
|
|
if (this.settings.autoEncloseSub_toggle) {
|
|
let last_subscript = current_line.lastIndexOf('_', position.ch);
|
|
if (last_subscript != -1 && last_subscript > last_math) {
|
|
const letter_after_subscript = editor.getRange({ line: position.line, ch: last_subscript + 1 }, { line: position.line, ch: last_subscript + 2 });
|
|
if (letter_after_subscript != "{" &&
|
|
(position.ch - last_subscript) <= 10) {
|
|
editor.replaceRange("}", position);
|
|
editor.replaceRange("{", { line: position.line, ch: last_subscript + 1 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// retrieve the last unbracketed superscript
|
|
let last_superscript = current_line.lastIndexOf('^', position.ch);
|
|
while (last_superscript != -1) {
|
|
const two_letters_after_superscript = editor.getRange({ line: position.line, ch: last_superscript + 1 }, { line: position.line, ch: last_superscript + 3 });
|
|
if (two_letters_after_superscript[0] == '{' || two_letters_after_superscript == ' {') {
|
|
last_superscript = current_line.lastIndexOf('^', last_superscript - 1);
|
|
}
|
|
else if (last_superscript < last_math) {
|
|
last_superscript = -1;
|
|
break;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
// retrieve the last divide symbol
|
|
let last_divide = current_line.lastIndexOf('/', position.ch - 2);
|
|
while (last_divide != -1) {
|
|
const around_divide = editor.getRange({ line: position.line, ch: last_divide - 1 }, { line: position.line, ch: last_divide + 2 });
|
|
if (around_divide[0] == ' ' && around_divide[2] == ' ') {
|
|
last_divide = current_line.lastIndexOf('^', last_divide - 1);
|
|
}
|
|
else if (last_divide < last_math) {
|
|
last_divide = -1;
|
|
break;
|
|
}
|
|
else {
|
|
break;
|
|
}
|
|
}
|
|
// perform autoEncloseSup
|
|
if (this.settings.autoEncloseSup_toggle) {
|
|
if (last_superscript > last_divide) {
|
|
// if any brackets from last sup to cursor still unclosed, dont do autoEncloseSup yet
|
|
const brackets = [['(', ')'], ['{', '}'], ['[', ']']];
|
|
if (!brackets.some(e => this.unclosed_bracket(editor, e[0], e[1], position.ch, last_superscript)[0])) {
|
|
this.autoEncloseSup(editor, event, last_superscript);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// perform autoFraction
|
|
if (this.settings.autoFraction_toggle && !this.withinText(editor, last_divide)) {
|
|
if (last_divide > last_dollar) {
|
|
const brackets = [['(', ')'], ['{', '}'], ['[', ']']];
|
|
// if any brackets in denominator still unclosed, dont do autoFraction yet
|
|
if (!brackets.some(e => this.unclosed_bracket(editor, e[0], e[1], position.ch, last_divide)[0])) {
|
|
this.autoFraction(editor, event, last_superscript);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// perform autoLargeBracket
|
|
if (this.settings.autoLargeBracket_toggle) {
|
|
let symbol_before = editor.getRange({ line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
if (symbol_before == ')' || symbol_before == ']') {
|
|
this.autoLargeBracket(editor, event);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 'Enter':
|
|
// perform Enter shortcut within matrix block
|
|
if (this.settings.addMatrixBlock_toggle) {
|
|
const begin_matrix = ['\\begin{' + this.settings.addMatrixBlock_parameter, "\\begin{matrix}", "\\begin{bmatrix}", "\\begin{Bmatrix}", "\\begin{vmatrix}", "\\begin{Vmatrix}", "\\begin{smallmatrix}"];
|
|
const end_matrix = ['\\end{' + this.settings.addMatrixBlock_parameter, "\\end{matrix}", "\\end{bmatrix}", "\\end{Bmatrix}", "\\end{vmatrix}", "\\end{Vmatrix}", "\\end{smallmatrix}"];
|
|
let state = false;
|
|
for (let i = 0; i < begin_matrix.length; i++) {
|
|
if (this.withinAnyBrackets_document(editor, begin_matrix[i], end_matrix[i])) {
|
|
state = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!event.shiftKey) {
|
|
if (state) {
|
|
editor.replaceSelection(' \\\\ ');
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
// perform Enter shortcut within align block
|
|
if (this.settings.addAlignBlock_toggle) {
|
|
if (this.withinAnyBrackets_document(editor, '\\begin{' + this.settings.addAlignBlock_parameter, '\\end{' + this.settings.addAlignBlock_parameter)) {
|
|
if (!event.shiftKey) {
|
|
editor.replaceSelection('\\\\\n&');
|
|
event.preventDefault();
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
// enter for cases block
|
|
if (this.settings.addCasesBlock_toggle) {
|
|
if (this.withinAnyBrackets_document(editor, '\\begin{cases}', '\\end{cases}')) {
|
|
editor.replaceSelection(' \\\\\n');
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
// double enter for $$
|
|
if (this.withinMath(editor)) {
|
|
const position = editor.getCursor();
|
|
const prev2_Char = editor.getRange({ line: position.line, ch: position.ch - 2 }, { line: position.line, ch: position.ch });
|
|
const next2_Char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 2 });
|
|
if (prev2_Char == "$$" && next2_Char == "$$") {
|
|
editor.replaceSelection('\n');
|
|
editor.setCursor(position);
|
|
}
|
|
}
|
|
return;
|
|
case 'Tab':
|
|
// perform Tab shortcut within matrix block
|
|
if (this.settings.addMatrixBlock_toggle) {
|
|
const begin_matrix = ['\\begin{' + this.settings.addMatrixBlock_parameter, "\\begin{matrix}", "\\begin{bmatrix}", "\\begin{Bmatrix}", "\\begin{vmatrix}", "\\begin{Vmatrix}", "\\begin{smallmatrix}"];
|
|
const end_matrix = ['\\end{' + this.settings.addMatrixBlock_parameter, "\\end{matrix}", "\\end{bmatrix}", "\\end{Bmatrix}", "\\end{vmatrix}", "\\end{Vmatrix}", "\\end{smallmatrix}"];
|
|
let state = false;
|
|
for (let i = 0; i < begin_matrix.length; i++) {
|
|
if (this.withinAnyBrackets_document(editor, begin_matrix[i], end_matrix[i])) {
|
|
state = true;
|
|
break;
|
|
}
|
|
}
|
|
if (state) {
|
|
editor.replaceSelection(' & ');
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
// Tab shortcut for cases block
|
|
if (this.settings.addCasesBlock_toggle) {
|
|
if (this.withinAnyBrackets_document(editor, '\\begin{cases}', '\\end{cases}')) {
|
|
editor.replaceSelection(' & ');
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
// Tab to go to next #tab with numbering or without numbering if there are no #tabs with numbers
|
|
const position = editor.getCursor();
|
|
const current_line = editor.getLine(position.line);
|
|
const indexed_tab_expr = /#tab(\d+)?/g;
|
|
let next_match;
|
|
let current_match;
|
|
while ((current_match = indexed_tab_expr.exec(current_line)) != null) {
|
|
if (!next_match || parseInt(current_match[1]) < parseInt(next_match[1]))
|
|
next_match = current_match;
|
|
}
|
|
if (next_match) {
|
|
const tab_position = next_match.index;
|
|
editor.replaceRange("", { line: position.line, ch: tab_position }, { line: position.line, ch: tab_position + next_match[0].length });
|
|
editor.setCursor({ line: position.line, ch: tab_position });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
// Tab to next close bracket
|
|
if (this.withinMath(editor)) {
|
|
const position = editor.getCursor();
|
|
const current_line = editor.getLine(position.line);
|
|
if (event.shiftKey) {
|
|
const close_symbols = ['}', ']', ')'];
|
|
const preceding_text = editor.getRange({ line: position.line, ch: 0 }, { line: position.line, ch: position.ch });
|
|
for (let i = preceding_text.length; i >= 0; i--) {
|
|
if (close_symbols.contains(preceding_text[i])) {
|
|
editor.setCursor({ line: position.line, ch: i });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
else if (position.ch - i > 1 && preceding_text[i] == "$") {
|
|
editor.setCursor({ line: position.line, ch: i + 1 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
else if (preceding_text.slice(-2) == "$$") {
|
|
editor.setCursor({ line: position.line, ch: position.ch - 2 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
else if (preceding_text[-1] == "$") {
|
|
editor.setCursor({ line: position.line, ch: position.ch - 1 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
const close_symbols = ['}', ']', ')', '$'];
|
|
const following_text = editor.getRange({ line: position.line, ch: position.ch + 1 }, { line: position.line, ch: current_line.length });
|
|
for (let i = 0; i < following_text.length; i++) {
|
|
if (close_symbols.contains(following_text[i])) {
|
|
editor.setCursor({ line: position.line, ch: position.ch + i + 1 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Tab out of $
|
|
if (this.withinMath(editor)) {
|
|
const position = editor.getCursor();
|
|
const next_2 = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 2 });
|
|
if (next_2 == "$$") {
|
|
editor.setCursor({ line: position.line, ch: position.ch + 2 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
else if (next_2[0] == "$") {
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
this.handleKeyPress = (cm, event) => {
|
|
if (['{', '[', '(', 'm'].contains(event.key)) {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return;
|
|
const editor = view.editor;
|
|
if (this.withinMath(editor)) {
|
|
const position = editor.getCursor();
|
|
const brackets = [['(', ')'], ['{', '}'], ['[', ']']];
|
|
const next_char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 1 });
|
|
const next_2char = editor.getRange({ line: position.line, ch: position.ch }, { line: position.line, ch: position.ch + 2 });
|
|
const followed_by_$spacetabnonedoubleslash = (['$', ' ', ' ', ''].contains(next_char) || next_2char == '\\\\');
|
|
switch (event.key) {
|
|
case '{':
|
|
if (this.settings.autoCloseCurly_toggle) {
|
|
if (!this.withinAnyBrackets_inline(editor, brackets) && followed_by_$spacetabnonedoubleslash) {
|
|
editor.replaceSelection('{}');
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
case '[':
|
|
if (this.settings.autoCloseSquare_toggle) {
|
|
if (!this.withinAnyBrackets_inline(editor, brackets) && followed_by_$spacetabnonedoubleslash) {
|
|
editor.replaceSelection('[]');
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
case '(':
|
|
if (this.settings.autoCloseRound_toggle) {
|
|
if (!this.withinAnyBrackets_inline(editor, brackets) && followed_by_$spacetabnonedoubleslash) {
|
|
editor.replaceSelection('()');
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
return;
|
|
case 'm':
|
|
if (!this.settings.autoSumLimit_toggle)
|
|
return;
|
|
if (editor.getRange({ line: position.line, ch: position.ch - 3 }, { line: position.line, ch: position.ch }) == '\\su') {
|
|
editor.replaceSelection('m\\limits');
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
//main functions
|
|
this.customShorthand = (editor, position) => {
|
|
let keyword = "";
|
|
let keyword_length = 0;
|
|
for (let i = 0; i < this.shorthand_array.length; i++) {
|
|
keyword_length = this.shorthand_array[i][0].length;
|
|
if (keyword_length > position.ch) {
|
|
continue;
|
|
}
|
|
else if (keyword_length == position.ch) {
|
|
keyword = "@" + editor.getRange({ line: position.line, ch: position.ch - keyword_length }, { line: position.line, ch: position.ch });
|
|
}
|
|
else {
|
|
keyword = editor.getRange({ line: position.line, ch: position.ch - keyword_length - 1 }, { line: position.line, ch: position.ch });
|
|
}
|
|
if (keyword[0].toLowerCase() == keyword[0].toUpperCase() ||
|
|
keyword[0] == "@") {
|
|
if (this.shorthand_array[i][0] == keyword.slice(-keyword_length) &&
|
|
this.shorthand_array[i][1] != keyword) {
|
|
const replace_slash = (keyword[0] == "\\" && this.shorthand_array[i][1][0] == "\\") ? 1 : 0;
|
|
const set_cursor_position = this.shorthand_array[i][1].indexOf("#cursor");
|
|
editor.replaceRange(this.shorthand_array[i][1], { line: position.line, ch: position.ch - keyword_length - replace_slash }, { line: position.line, ch: position.ch });
|
|
if (set_cursor_position != -1) {
|
|
editor.replaceRange("", { line: position.line, ch: position.ch - keyword_length - replace_slash + set_cursor_position }, { line: position.line, ch: position.ch - keyword_length - replace_slash + set_cursor_position + 7 });
|
|
editor.setCursor({ line: position.line, ch: position.ch - keyword_length - replace_slash + set_cursor_position });
|
|
}
|
|
else if (this.shorthand_array[i][1].slice(-2) == "{}") {
|
|
editor.setCursor({ line: position.line,
|
|
ch: position.ch + this.shorthand_array[i][1].length - keyword_length - 1 - replace_slash });
|
|
}
|
|
else ;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
this.autoEncloseSup = (editor, event, last_superscript) => {
|
|
// superscript bracketing
|
|
const position = editor.getCursor();
|
|
const letter_before_cursor = editor.getRange({ line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
if (last_superscript != -1 && letter_before_cursor != "^") {
|
|
const letter_after_superscript = editor.getRange({ line: position.line, ch: last_superscript + 1 }, { line: position.line, ch: last_superscript + 2 });
|
|
if (letter_after_superscript == '(' && letter_before_cursor == ')' && position.ch - last_superscript > 6) {
|
|
editor.replaceRange('}', { line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
editor.replaceRange('{', { line: position.line, ch: last_superscript + 1 }, { line: position.line, ch: last_superscript + 2 });
|
|
event.preventDefault();
|
|
return true;
|
|
}
|
|
else if (letter_after_superscript == ' ') {
|
|
editor.replaceSelection('}');
|
|
editor.replaceRange('{', { line: position.line, ch: last_superscript + 2 });
|
|
event.preventDefault();
|
|
return true;
|
|
}
|
|
else {
|
|
editor.replaceSelection('}');
|
|
editor.replaceRange('{', { line: position.line, ch: last_superscript + 1 });
|
|
event.preventDefault();
|
|
return true;
|
|
}
|
|
}
|
|
else {
|
|
return false;
|
|
}
|
|
};
|
|
this.autoFraction = (editor, event, last_superscript) => {
|
|
const position = editor.getCursor();
|
|
const current_line = editor.getLine(position.line);
|
|
let last_divide = current_line.lastIndexOf('/', position.ch - 1);
|
|
// if cursor is preceeded by a close bracket, and the corresponding open bracket
|
|
// is found before "/", remove the brackets and enclose whole expression using \frac
|
|
const letter_before_cursor = editor.getRange({ line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
// if there are any brackets unclosed before divide symbol,
|
|
// include the open brackets into stop_symbols
|
|
const brackets = [['(', ')'], ['{', '}'], ['[', ']']];
|
|
let stop_brackets = [];
|
|
for (let i = 0; i < brackets.length; i++) {
|
|
if (letter_before_cursor == brackets[i][1]) {
|
|
const open_brackets = this.unclosed_bracket(editor, brackets[i][0], brackets[i][1], position.ch - 1, 0)[1];
|
|
const pos_of_the_open_bracket = open_brackets[open_brackets.length - 1];
|
|
if (pos_of_the_open_bracket < last_divide) {
|
|
editor.replaceRange('}', { line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
editor.replaceRange('}{', { line: position.line, ch: last_divide }, { line: position.line, ch: last_divide + 1 });
|
|
editor.replaceRange('\\frac{', { line: position.line, ch: pos_of_the_open_bracket }, { line: position.line, ch: pos_of_the_open_bracket + 1 });
|
|
event.preventDefault();
|
|
return;
|
|
}
|
|
}
|
|
stop_brackets.push(...this.unclosed_bracket(editor, brackets[i][0], brackets[i][1], last_divide, 0)[1]);
|
|
}
|
|
let frac = 0;
|
|
// if numerator is enclosed by (), place frac in front of () and remove ()
|
|
let numerator_remove_bracket = 0;
|
|
if (editor.getRange({ line: position.line, ch: last_divide - 1 }, { line: position.line, ch: last_divide }) == ')') {
|
|
const numerator_open_bracket = this.unclosed_bracket(editor, '(', ')', last_divide - 1, 0)[1].slice(-1)[0];
|
|
frac = numerator_open_bracket - 1;
|
|
numerator_remove_bracket = 1;
|
|
}
|
|
else {
|
|
const stop_symbols = ['$', '=', '>', '<', ',', '/', ' '];
|
|
const symbol_positions = stop_symbols.map(e => current_line.lastIndexOf(e, last_divide - 1));
|
|
frac = Math.max(last_superscript, ...symbol_positions, ...stop_brackets);
|
|
}
|
|
// if denominator is enclosed by (), remove ()
|
|
const denominator = editor.getRange({ line: position.line, ch: last_divide + 1 }, { line: position.line, ch: position.ch });
|
|
let denominator_remove_bracket = 0;
|
|
if (denominator.slice(-1)[0] == ')') {
|
|
const denominator_open_bracket = this.unclosed_bracket(editor, '(', ')', position.ch - 1, 0)[1].slice(-1)[0];
|
|
if (denominator_open_bracket == last_divide + 1) {
|
|
denominator_remove_bracket = 1;
|
|
}
|
|
}
|
|
// perform \frac replace
|
|
editor.replaceRange('}', { line: position.line, ch: position.ch - denominator_remove_bracket }, { line: position.line, ch: position.ch });
|
|
editor.replaceRange('}{', { line: position.line, ch: last_divide - numerator_remove_bracket }, { line: position.line, ch: last_divide + 1 + denominator_remove_bracket });
|
|
editor.replaceRange('\\frac{', { line: position.line, ch: frac + 1 }, { line: position.line, ch: frac + 1 + numerator_remove_bracket });
|
|
event.preventDefault();
|
|
return;
|
|
};
|
|
this.autoFractionCM6 = (editor, last_superscript) => {
|
|
const position = editor.getCursor();
|
|
const current_line = editor.getLine(position.line);
|
|
let last_divide = current_line.lastIndexOf('/', position.ch - 1);
|
|
// if cursor is preceeded by a close bracket, and the corresponding open bracket
|
|
// is found before "/", remove the brackets and enclose whole expression using \frac
|
|
const letter_before_cursor = editor.getRange({ line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
// if there are any brackets unclosed before divide symbol,
|
|
// include the open brackets into stop_symbols
|
|
const brackets = [['(', ')'], ['{', '}'], ['[', ']']];
|
|
let stop_brackets = [];
|
|
for (let i = 0; i < brackets.length; i++) {
|
|
if (letter_before_cursor == brackets[i][1]) {
|
|
const open_brackets = this.unclosed_bracket(editor, brackets[i][0], brackets[i][1], position.ch - 1, 0)[1];
|
|
const pos_of_the_open_bracket = open_brackets[open_brackets.length - 1];
|
|
if (pos_of_the_open_bracket < last_divide) {
|
|
editor.replaceRange('}', { line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
editor.replaceRange('}{', { line: position.line, ch: last_divide }, { line: position.line, ch: last_divide + 1 });
|
|
editor.replaceRange('\\frac{', { line: position.line, ch: pos_of_the_open_bracket }, { line: position.line, ch: pos_of_the_open_bracket + 1 });
|
|
return true;
|
|
}
|
|
}
|
|
stop_brackets.push(...this.unclosed_bracket(editor, brackets[i][0], brackets[i][1], last_divide, 0)[1]);
|
|
}
|
|
let frac = 0;
|
|
// if numerator is enclosed by (), place frac in front of () and remove ()
|
|
let numerator_remove_bracket = 0;
|
|
if (editor.getRange({ line: position.line, ch: last_divide - 1 }, { line: position.line, ch: last_divide }) == ')') {
|
|
const numerator_open_bracket = this.unclosed_bracket(editor, '(', ')', last_divide - 1, 0)[1].slice(-1)[0];
|
|
frac = numerator_open_bracket - 1;
|
|
numerator_remove_bracket = 1;
|
|
}
|
|
else {
|
|
const stop_symbols = ['$', '=', '>', '<', ',', '/', ' '];
|
|
const symbol_positions = stop_symbols.map(e => current_line.lastIndexOf(e, last_divide - 1));
|
|
frac = Math.max(last_superscript, ...symbol_positions, ...stop_brackets);
|
|
}
|
|
// if denominator is enclosed by (), remove ()
|
|
const denominator = editor.getRange({ line: position.line, ch: last_divide + 1 }, { line: position.line, ch: position.ch });
|
|
let denominator_remove_bracket = 0;
|
|
if (denominator.slice(-1)[0] == ')') {
|
|
const denominator_open_bracket = this.unclosed_bracket(editor, '(', ')', position.ch - 1, 0)[1].slice(-1)[0];
|
|
if (denominator_open_bracket == last_divide + 1) {
|
|
denominator_remove_bracket = 1;
|
|
}
|
|
}
|
|
// perform \frac replace
|
|
editor.replaceRange('}', { line: position.line, ch: position.ch - denominator_remove_bracket }, { line: position.line, ch: position.ch });
|
|
editor.replaceRange('}{', { line: position.line, ch: last_divide - numerator_remove_bracket }, { line: position.line, ch: last_divide + 1 + denominator_remove_bracket });
|
|
editor.replaceRange('\\frac{', { line: position.line, ch: frac + 1 }, { line: position.line, ch: frac + 1 + numerator_remove_bracket });
|
|
const pos = editor.getCursor();
|
|
editor.setCursor({ line: pos.line, ch: pos.ch + 1 - denominator_remove_bracket });
|
|
return true;
|
|
};
|
|
this.autoLargeBracket = (editor, event) => {
|
|
const position = editor.getCursor();
|
|
let brackets = [['[', ']'], ['(', ')']];
|
|
const prev_char = editor.getRange({ line: position.line, ch: position.ch - 1 }, { line: position.line, ch: position.ch });
|
|
const current_brackets = brackets.filter(e => e[1] == prev_char)[0];
|
|
if (current_brackets.length == 0)
|
|
return;
|
|
const open_bracket = this.unclosed_bracket(editor, current_brackets[0], current_brackets[1], position.ch - 1, 0)[1].slice(-1)[0];
|
|
const text = editor.getRange({ line: position.line, ch: open_bracket }, { line: position.line, ch: position.ch });
|
|
const large_operators = ['\\sum', '\\int', '\\frac', '\\dfrac'];
|
|
let large_operators_locations = [];
|
|
for (let i = 0; i < large_operators.length; i++) {
|
|
let found = 0;
|
|
while (found != -1) {
|
|
found = text.indexOf(large_operators[i], found + 1);
|
|
if (found != -1) {
|
|
large_operators_locations.push(found + open_bracket);
|
|
}
|
|
}
|
|
}
|
|
const current_line = editor.getLine(position.line);
|
|
let retVal = false;
|
|
for (let i = 0; i < large_operators_locations.length; i++) {
|
|
let left_array = [];
|
|
let right_array = [];
|
|
for (let j = 0; j < brackets.length; j++) {
|
|
left_array.push(...this.unclosed_bracket(editor, brackets[j][0], brackets[j][1], large_operators_locations[i], 0)[1]);
|
|
right_array.push(...this.unclosed_bracket(editor, brackets[j][0], brackets[j][1], current_line.length, large_operators_locations[i], false)[1]);
|
|
}
|
|
for (let k = right_array.length - 1; k > -1; k--) {
|
|
// check if unclosed brackets already appended with \right
|
|
let check_right = editor.getRange({ line: position.line, ch: right_array[k] - 6 }, { line: position.line, ch: right_array[k] });
|
|
if (check_right != '\\right') {
|
|
editor.replaceRange('\\right', { line: position.line, ch: right_array[k] });
|
|
event.preventDefault();
|
|
retVal = true;
|
|
}
|
|
}
|
|
for (let l = left_array.length - 1; l > -1; l--) {
|
|
// check if unclosed brackets already appended with \left
|
|
let check_left = editor.getRange({ line: position.line, ch: left_array[l] - 5 }, { line: position.line, ch: left_array[l] });
|
|
if (check_left != '\\left') {
|
|
editor.replaceRange('\\left', { line: position.line, ch: left_array[l] });
|
|
event.preventDefault();
|
|
retVal = true;
|
|
}
|
|
}
|
|
}
|
|
return retVal;
|
|
};
|
|
//utility functions
|
|
this.unclosed_bracket = (editor, open_symbol, close_symbol, before, after, unclosed_open_symbol = true //false for unclosed_close_symbol
|
|
) => {
|
|
// determine if there are unclosed bracket within the range specified by before and after
|
|
const position = editor.getCursor();
|
|
const text = editor.getRange({ line: position.line, ch: after }, { line: position.line, ch: before });
|
|
let open_array = [];
|
|
let close_array = [];
|
|
for (let i = 0; i < text.length; i++) {
|
|
switch (text[i]) {
|
|
case open_symbol:
|
|
open_array.push(after + i);
|
|
break;
|
|
case close_symbol:
|
|
if (open_array.length > 0) {
|
|
open_array.pop();
|
|
}
|
|
else {
|
|
close_array.push(after + i);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
if (unclosed_open_symbol) {
|
|
return [open_array.length > 0, open_array];
|
|
}
|
|
else {
|
|
return [close_array.length > 0, close_array];
|
|
}
|
|
};
|
|
this.withinText = (editor, at_where) => {
|
|
// check if within text{}
|
|
const position = editor.getCursor();
|
|
const bracket_locations = this.unclosed_bracket(editor, '{', '}', at_where, 0)[1];
|
|
return bracket_locations.some(loc => editor.getRange({ line: position.line, ch: loc - 4 }, { line: position.line, ch: loc }) == "text");
|
|
};
|
|
this.withinMath = (editor) => {
|
|
// check if cursor within $$
|
|
const position = editor.getCursor();
|
|
const current_line = editor.getLine(position.line);
|
|
let cursor_index = position.ch;
|
|
let from = 0;
|
|
let found = current_line.indexOf('$', from);
|
|
while (found != -1 && found < cursor_index) {
|
|
let next_char = editor.getRange({ line: position.line, ch: found + 1 }, { line: position.line, ch: found + 2 });
|
|
let prev_char = editor.getRange({ line: position.line, ch: found - 1 }, { line: position.line, ch: found });
|
|
if (next_char == '$' || prev_char == '$' || next_char == ' ') {
|
|
from = found + 1;
|
|
found = current_line.indexOf('$', from);
|
|
continue;
|
|
}
|
|
else {
|
|
from = found + 1;
|
|
let next_found = current_line.indexOf('$', from);
|
|
if (next_found == -1) {
|
|
return false;
|
|
}
|
|
else if (cursor_index > found && cursor_index <= next_found) {
|
|
return true;
|
|
}
|
|
else {
|
|
from = next_found + 1;
|
|
found = current_line.indexOf('$', from);
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
const document_text = editor.getValue();
|
|
cursor_index = editor.posToOffset(position);
|
|
from = 0;
|
|
found = document_text.indexOf('$$', from);
|
|
let count = 0;
|
|
while (found != -1 && found < cursor_index) {
|
|
count += 1;
|
|
from = found + 2;
|
|
found = document_text.indexOf('$$', from);
|
|
}
|
|
return count % 2 == 1;
|
|
};
|
|
this.withinAnyBrackets_inline = (editor, brackets) => {
|
|
const position = editor.getCursor();
|
|
const current_line = editor.getLine(position.line);
|
|
return brackets.some(e => this.unclosed_bracket(editor, e[0], e[1], position.ch, 0)[0] &&
|
|
this.unclosed_bracket(editor, e[0], e[1], current_line.length, position.ch, false)[0]);
|
|
};
|
|
this.withinAnyBrackets_document = (editor, open_symbol, close_symbol) => {
|
|
const document_text = editor.getValue();
|
|
const cursorPos = editor.getCursor();
|
|
const cursor_index = editor.posToOffset(cursorPos);
|
|
// count open symbols
|
|
let from = 0;
|
|
let found = document_text.indexOf(open_symbol, from);
|
|
let count = 0;
|
|
while (found != -1 && found < cursor_index) {
|
|
count += 1;
|
|
from = found + 1;
|
|
found = document_text.indexOf(open_symbol, from);
|
|
}
|
|
const open_symbol_counts = count;
|
|
// count close symbols
|
|
from = 0;
|
|
found = document_text.indexOf(close_symbol, from);
|
|
count = 0;
|
|
while (found != -1 && found < cursor_index) {
|
|
count += 1;
|
|
from = found + 1;
|
|
found = document_text.indexOf(close_symbol, from);
|
|
}
|
|
const close_symbol_counts = count;
|
|
return open_symbol_counts > close_symbol_counts;
|
|
};
|
|
}
|
|
onload() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
this.registerEditorExtension(this.makeExtensionThing());
|
|
yield this.loadSettings();
|
|
// preprocess shorthand array
|
|
let shorthands = this.settings.customShorthand_parameter;
|
|
while (shorthands.slice(-2) == "\n") {
|
|
shorthands = shorthands.slice(0, -2);
|
|
}
|
|
if (shorthands.slice(-1) == ";") {
|
|
shorthands = shorthands.slice(0, -1);
|
|
}
|
|
if (shorthands.lastIndexOf(";\n") == -1) {
|
|
this.shorthand_array = shorthands.split(",").map(item => item.split(":"));
|
|
}
|
|
else if (shorthands.lastIndexOf(":::") == -1) {
|
|
this.shorthand_array = shorthands.split(";\n").map(item => item.split(":"));
|
|
}
|
|
else {
|
|
this.shorthand_array = shorthands.split(";\n").map(item => item.split(":::"));
|
|
}
|
|
// preprocess autoAlign array
|
|
if (this.settings.autoAlignSymbols.trim() == "") {
|
|
this.autoAlign_array = [];
|
|
}
|
|
else {
|
|
this.autoAlign_array = this.settings.autoAlignSymbols.split(" ");
|
|
}
|
|
this.app.workspace.onLayoutReady(() => {
|
|
this.registerCodeMirror((cm) => {
|
|
cm.on('vim-mode-change', this.handleVimModeChange);
|
|
cm.on('keydown', this.handleKeyDown);
|
|
cm.on('keypress', this.handleKeyPress);
|
|
});
|
|
this.addSettingTab(new QuickLatexSettingTab(this.app, this));
|
|
this.addCommand({
|
|
id: 'addAlignBlock',
|
|
name: 'Add Align Block',
|
|
hotkeys: [
|
|
{
|
|
modifiers: ['Alt', 'Shift'],
|
|
key: 'A',
|
|
},
|
|
],
|
|
editorCallback: (editor) => this.addAlignBlock(editor),
|
|
});
|
|
this.addCommand({
|
|
id: 'addInlineMath',
|
|
name: 'Add Inline Math',
|
|
hotkeys: [
|
|
{
|
|
modifiers: ['Mod'],
|
|
key: 'M',
|
|
},
|
|
],
|
|
editorCallback: (editor) => this.addInlineMath(editor),
|
|
});
|
|
this.addCommand({
|
|
id: 'addBlockMath',
|
|
name: 'Add Block Math',
|
|
hotkeys: [
|
|
{
|
|
modifiers: ['Mod', 'Shift'],
|
|
key: 'M',
|
|
},
|
|
],
|
|
editorCallback: (editor) => this.addBlockMath(editor),
|
|
});
|
|
this.addCommand({
|
|
id: 'addMatrixBlock',
|
|
name: 'Add Matrix Block',
|
|
hotkeys: [
|
|
{
|
|
modifiers: ['Alt', 'Shift'],
|
|
key: 'M',
|
|
},
|
|
],
|
|
editorCallback: (editor) => this.addMatrixBlock(editor),
|
|
});
|
|
this.addCommand({
|
|
id: 'addCasesBlock',
|
|
name: 'Add Cases Block',
|
|
hotkeys: [
|
|
{
|
|
modifiers: ['Alt', 'Shift'],
|
|
key: 'C',
|
|
},
|
|
],
|
|
editorCallback: (editor) => this.addCasesBlock(editor),
|
|
});
|
|
});
|
|
});
|
|
}
|
|
addInlineMath(editor) {
|
|
if (!this.settings.useMathKeyboardShortcut_toggle)
|
|
return false;
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
if (editor.getSelection().length > 0) {
|
|
// enclose selected text
|
|
const anchor = editor.getCursor("anchor");
|
|
const head = editor.getCursor("head");
|
|
editor.replaceSelection(`$${editor.getSelection()}$`);
|
|
if (anchor.line > head.line) {
|
|
editor.setSelection({ line: anchor.line, ch: anchor.ch }, { line: head.line, ch: head.ch + 1 });
|
|
}
|
|
else if (anchor.line < head.line) {
|
|
editor.setSelection({ line: anchor.line, ch: anchor.ch + 1 }, { line: head.line, ch: head.ch });
|
|
}
|
|
else {
|
|
editor.setSelection({ line: anchor.line, ch: anchor.ch + 1 }, { line: head.line, ch: head.ch + 1 });
|
|
}
|
|
}
|
|
else {
|
|
const position = editor.getCursor();
|
|
editor.replaceSelection("$$");
|
|
editor.setCursor({ line: position.line, ch: position.ch + 1 });
|
|
}
|
|
return true;
|
|
}
|
|
addBlockMath(editor) {
|
|
if (!this.settings.useMathKeyboardShortcut_toggle)
|
|
return false;
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return false;
|
|
if (editor.getSelection().length > 0) {
|
|
// enclose selected text
|
|
const anchor = editor.getCursor("anchor");
|
|
const head = editor.getCursor("head");
|
|
editor.replaceSelection(`$$${editor.getSelection()}$$`);
|
|
if (anchor.line > head.line) {
|
|
editor.setSelection({ line: anchor.line, ch: anchor.ch }, { line: head.line, ch: head.ch + 2 });
|
|
}
|
|
else if (anchor.line < head.line) {
|
|
editor.setSelection({ line: anchor.line, ch: anchor.ch + 2 }, { line: head.line, ch: head.ch });
|
|
}
|
|
else {
|
|
editor.setSelection({ line: anchor.line, ch: anchor.ch + 2 }, { line: head.line, ch: head.ch + 2 });
|
|
}
|
|
}
|
|
else {
|
|
const position = editor.getCursor();
|
|
editor.replaceSelection("$$$$");
|
|
editor.setCursor({ line: position.line, ch: position.ch + 2 });
|
|
}
|
|
return true;
|
|
}
|
|
addAlignBlock(editor) {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return;
|
|
if (!this.settings.addAlignBlock_toggle)
|
|
return;
|
|
const selected_text = editor.getSelection();
|
|
editor.replaceSelection('\\begin{' + this.settings.addAlignBlock_parameter + '}\n' +
|
|
selected_text +
|
|
'\n\\end{' + this.settings.addAlignBlock_parameter + '}');
|
|
const position = editor.getCursor();
|
|
editor.setCursor({ line: position.line - 1, ch: editor.getLine(position.line - 1).length });
|
|
}
|
|
addMatrixBlock(editor) {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return;
|
|
if (!this.settings.addMatrixBlock_toggle)
|
|
return;
|
|
editor.replaceSelection('\\begin{' + this.settings.addMatrixBlock_parameter + '}' +
|
|
'\\end{' + this.settings.addMatrixBlock_parameter + '}');
|
|
const position = editor.getCursor();
|
|
const retract_length = ('\\end{' + this.settings.addMatrixBlock_parameter + '}').length;
|
|
editor.setCursor({ line: position.line, ch: position.ch - retract_length });
|
|
}
|
|
addCasesBlock(editor) {
|
|
const view = this.app.workspace.getActiveViewOfType(obsidian.MarkdownView);
|
|
if (!view)
|
|
return;
|
|
if (!this.settings.addCasesBlock_toggle)
|
|
return;
|
|
const selected_text = editor.getSelection();
|
|
editor.replaceSelection('\\begin{cases}\n' +
|
|
selected_text +
|
|
'\n\\end{cases}');
|
|
const position = editor.getCursor();
|
|
editor.setCursor({ line: position.line - 1, ch: editor.getLine(position.line - 1).length });
|
|
}
|
|
// Settings load and save
|
|
loadSettings() {
|
|
return __awaiter(this, void 0, void 0, function* () {
|
|
this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData());
|
|
});
|
|
}
|
|
;
|
|
onunload() {
|
|
this.app.workspace.iterateCodeMirrors((cm) => {
|
|
cm.off('vim-mode-change', this.handleVimModeChange);
|
|
cm.off('keydown', this.handleKeyDown);
|
|
cm.off('keypress', this.handleKeyPress);
|
|
});
|
|
}
|
|
}
|
|
class QuickLatexSettingTab extends obsidian.PluginSettingTab {
|
|
constructor(app, plugin) {
|
|
super(app, plugin);
|
|
this.plugin = plugin;
|
|
}
|
|
display() {
|
|
const { containerEl } = this;
|
|
containerEl.empty();
|
|
containerEl.createEl('h2', { text: 'Quick Latex for Obsidian - Settings' });
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Autoclose $$ symbols')
|
|
.setDesc('Typing one $ symbol will automatically lose with another $ symbol ' +
|
|
'(best used with "Move cursor between $$ symbols" function')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.autoCloseMath_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.autoCloseMath_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Shortcut for inline and block math')
|
|
.setDesc('Enable keyboard shortcuts for inline ($...$) and block ($$...$$) math. ' +
|
|
'Default: ctrl+m (cmd+m on mac) for inline and ctrl+shift+m (cmd+shift+m on mac) for block.')
|
|
.addToggle((toggle) => {
|
|
toggle.setValue(this.plugin.settings.useMathKeyboardShortcut_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.useMathKeyboardShortcut_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
}));
|
|
});
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Move cursor between $$ symbols')
|
|
.setDesc('Typing two consecutive $ symbols will automatically shift the cursor in between the $$ symbols')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.moveIntoMath_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.moveIntoMath_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Enclose selected expression with math symbol $$')
|
|
.setDesc('Select an expression and press "$" key will automatically ' +
|
|
'enclose the expression with the math symbols.')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.encloseSelection_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.encloseSelection_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Autoclose {} curly brackets')
|
|
.setDesc('Typing "{" will automatically close with "}"')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.autoCloseCurly_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.autoCloseCurly_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Autoclose [] square brackets')
|
|
.setDesc('Typing "[" will automatically close with "]"')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.autoCloseSquare_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.autoCloseSquare_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Autoclose () round brackets')
|
|
.setDesc('Typing "(" will automatically close with ")"')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.autoCloseRound_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.autoCloseRound_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Auto append "\\limits" after "\\sum"')
|
|
.setDesc('Typing "\\sum" will automatically append "\\limits" to shorten the syntax' +
|
|
' for proper display of the limits for summation symbol.')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.autoSumLimit_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.autoSumLimit_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Auto enlarge brackets that contains \\sum, \\int or \\frac')
|
|
.setDesc('Place cursor right after a () or [] bracketed expression that contains either ' +
|
|
'\\sum, \\int or \\frac and press the space key, the outermost brackets will be' +
|
|
' appended with \\left and \\right in order to display larger brackets to enclose these big expressions.')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.autoLargeBracket_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.autoLargeBracket_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Auto enclose expression after superscipt with {}')
|
|
.setDesc('Typing expression after superscript "^" symbol follow by a "space" key ' +
|
|
'will automatically surround the expression with "{}"')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.autoEncloseSup_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.autoEncloseSup_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Auto enclose expression after subscript with {}')
|
|
.setDesc('Typing expression after subscript "_" symbol follow by a "space" key ' +
|
|
'will automatically surround the expression with "{}". ' +
|
|
'Note: expression more than 10 characters long will be ignored.')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.autoEncloseSub_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.autoEncloseSub_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Type "/" instead of \\frac{}{}')
|
|
.setDesc('Use "/" symbol for quickly typing fractions. eg. type "1/2" followed by a "space" key' +
|
|
' to transform to \\frac{1}{2}')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.autoFraction_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.autoFraction_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Shortcut for Align Block')
|
|
.setDesc('Use shortcut key to quickly insert \\begin{align*} \\end{align*} block. ' +
|
|
'Default: "Alt+Shift+A" (Mac: "Option+Shift+A")')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.addAlignBlock_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.addAlignBlock_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Align Block Parameter')
|
|
.setDesc('Set the text parameter in \\begin{parameter} and \\end{parameter}.')
|
|
.addText((text) => text
|
|
.setPlaceholder('default: align*')
|
|
.setValue(this.plugin.settings.addAlignBlock_parameter)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.addAlignBlock_parameter = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('【NEW!】Auto-align at these symbols')
|
|
.setDesc('When within the align block, the align symbol "&" will be automatically added before these symbols. (separate by spaces)')
|
|
.addText((text) => text
|
|
.setValue(this.plugin.settings.autoAlignSymbols)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.autoAlignSymbols = value;
|
|
if (value == "") {
|
|
this.plugin.autoAlign_array = [];
|
|
}
|
|
else {
|
|
this.plugin.autoAlign_array = value.split(" ");
|
|
}
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Shortcut for Cases Block')
|
|
.setDesc('Use shortcut key to quickly insert \\begin{cases} \\end{cases} block. ' +
|
|
'Default: "Alt+Shift+C" (Mac: "Option+Shift+C")')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.addCasesBlock_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.addCasesBlock_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Use shift-enter for line break in align and cases block')
|
|
.setDesc('For align and cases block above, pressing enter automatically adds line break symbol "\\" or "&". Switch here to use shift-enter instead.')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.shiftEnter_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.shiftEnter_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Shortcut for Matrix Block')
|
|
.setDesc('Use shortcut key to quickly insert \\begin{pmatrix} \\end{pmatrix} block. ' +
|
|
'Default: "Alt+Shift+M" (Mac: "Option+Shift+M")')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.addMatrixBlock_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.addMatrixBlock_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Matrix Block Parameter')
|
|
.setDesc('Set the text parameter in \\begin{parameter} and \\end{parameter}.')
|
|
.addText((text) => text
|
|
.setPlaceholder('default: pmatrix')
|
|
.setValue(this.plugin.settings.addMatrixBlock_parameter)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.addMatrixBlock_parameter = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Greek symbols math mode')
|
|
.setDesc('Automatically surround commands to insert Greek character written outside math mode with math chars. ' +
|
|
'Eg, typing \\alpha followed by space outside math mode will be replaced with "$\\alpha$"')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.autoGreekCommandMathMode_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.autoGreekCommandMathMode_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Custom Shorthand')
|
|
.setDesc('Use custom shorthand (can be multiple letters) for common latex strings. ' +
|
|
'Eg, typing "al" followed by "space/tab" key will replace with "\\alpha"')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.customShorthand_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.customShorthand_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Use Tab to complete custom shorthand')
|
|
.setDesc('Use Tab instead of space to complete custom shorthand.')
|
|
.addToggle((toggle) => toggle
|
|
.setValue(this.plugin.settings.useTabtoComplete_toggle)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.useTabtoComplete_toggle = value;
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
this.display();
|
|
})));
|
|
new obsidian.Setting(containerEl)
|
|
.setName('Custom Shorthand Parameter')
|
|
.setDesc('Separate the multi-letters shorthand and the snippet with ":::" and ' +
|
|
'end each set of shorthand snippet pair by "---" and a newline. ' +
|
|
'For expressions that end with "{}", the cursor will automatically be placed within the bracket. ' +
|
|
'Alternatively, you can type "#cursor" within the snippet to set the cursor location after replacement. ' +
|
|
'You can also include "#tab" within the snippet for use cases such as multiple {}s (e.g. \\binom{#cursor}{#tab}). ' +
|
|
'Pressing tab key in such cases will jump the cursor to the next "#tab" keyword. ' +
|
|
'Numbers after each "#tab" can be added to define the order in which to jump between the tabs (e.g. \\left#cursor #tab2 \\right#tab1 will first jump to #tab1 then back to #tab2). ' +
|
|
'Shorthands now support multiline snippets too! ' +
|
|
'(try uninstall then reinstalling the plugin to see the new set of shorthands.) ' +
|
|
'【NOTE】For old users, please kindly replace ":" with ":::" in your custom shorthand parameter.')
|
|
.setClass("text-snippets-class")
|
|
.addTextArea((text) => text
|
|
.setValue(this.plugin.settings.customShorthand_parameter)
|
|
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
|
|
this.plugin.settings.customShorthand_parameter = value;
|
|
while (value.slice(-2) == "\n") {
|
|
value = value.slice(0, -1);
|
|
}
|
|
if (value.slice(-1) == ";") {
|
|
value = value.slice(0, -1);
|
|
}
|
|
if (value.lastIndexOf(";\n") == -1) {
|
|
this.plugin.shorthand_array = value.split(",").map(item => item.split(":"));
|
|
}
|
|
else if (value.lastIndexOf(":::") == -1) {
|
|
this.plugin.shorthand_array = value.split(";\n").map(item => item.split(":"));
|
|
}
|
|
else {
|
|
this.plugin.shorthand_array = value.split(";\n").map(item => item.split(":::"));
|
|
}
|
|
yield this.plugin.saveData(this.plugin.settings);
|
|
})));
|
|
}
|
|
;
|
|
}
|
|
|
|
module.exports = QuickLatexPlugin;
|
|
|
|
|
|
/* nosourcemap */ |