Files
Polsl-Notes/.obsidian/plugins/obsidian-completr/main.js
2022-10-25 16:01:18 +02:00

2520 lines
77 KiB
JavaScript

/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var __async = (__this, __arguments, generator) => {
return new Promise((resolve, reject) => {
var fulfilled = (value) => {
try {
step(generator.next(value));
} catch (e) {
reject(e);
}
};
var rejected = (value) => {
try {
step(generator.throw(value));
} catch (e) {
reject(e);
}
};
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
step((generator = generator.apply(__this, __arguments)).next());
});
};
// src/main.ts
var main_exports = {};
__export(main_exports, {
default: () => CompletrPlugin
});
module.exports = __toCommonJS(main_exports);
var import_obsidian5 = require("obsidian");
// src/snippet_manager.ts
var import_view2 = require("@codemirror/view");
// src/editor_helpers.ts
function posFromIndex(doc, offset) {
let line = doc.lineAt(offset);
return { line: line.number - 1, ch: offset - line.from };
}
function indexFromPos(doc, pos) {
const ch = pos.ch;
const line = doc.line(pos.line + 1);
return Math.min(line.from + Math.max(0, ch), line.to);
}
function editorToCodeMirrorState(editor) {
return editor.cm.state;
}
function editorToCodeMirrorView(editor) {
return editor.cm;
}
function maybeLowerCase(str, lowerCase) {
return lowerCase ? str.toLowerCase() : str;
}
function matchWordBackwards(editor, cursor, charPredicate, maxLookBackDistance = 50) {
let query = "", separatorChar = null;
let lookBackEnd = Math.max(0, cursor.ch - maxLookBackDistance);
for (let i = cursor.ch - 1; i >= lookBackEnd; i--) {
const prevChar = editor.getRange(__spreadProps(__spreadValues({}, cursor), { ch: i }), __spreadProps(__spreadValues({}, cursor), { ch: i + 1 }));
if (!charPredicate(prevChar)) {
separatorChar = prevChar;
break;
}
query = prevChar + query;
}
return { query, separatorChar };
}
function isInFrontMatterBlock(editor, pos) {
if (pos.line === 0)
return false;
const bounds = getFrontMatterBounds(editor);
if (!bounds)
return false;
return pos.line > bounds.startLine && pos.line < bounds.endLine;
}
function getFrontMatterBounds(editor) {
let startLine = -1;
for (let i = 0; i < Math.min(5, editor.lastLine()); i++) {
if (editor.getLine(i) !== "---")
continue;
startLine = i;
break;
}
if (startLine === -1)
return null;
let endLine = -1;
for (let i = startLine + 1; i <= Math.min(50, editor.lastLine()); i++) {
if (editor.getLine(i) !== "---")
continue;
endLine = i;
break;
}
if (endLine === -1)
return null;
return { startLine, endLine };
}
var _BlockType = class {
constructor(c, isMultiLine, otherType0 = null) {
this.c = c;
this.isMultiLine = isMultiLine;
this.otherType0 = otherType0;
}
get isDollarBlock() {
return this === _BlockType.DOLLAR_SINGLE || this === _BlockType.DOLLAR_MULTI;
}
get isCodeBlock() {
return !this.isDollarBlock;
}
get otherType() {
return this.otherType0;
}
};
var BlockType = _BlockType;
BlockType.DOLLAR_MULTI = new _BlockType("$$", true);
BlockType.DOLLAR_SINGLE = new _BlockType("$", false, _BlockType.DOLLAR_MULTI);
BlockType.CODE_MULTI = new _BlockType("```", true);
BlockType.CODE_SINGLE = new _BlockType("`", false, _BlockType.CODE_MULTI);
(() => {
_BlockType.DOLLAR_MULTI.otherType0 = _BlockType.DOLLAR_SINGLE;
_BlockType.CODE_MULTI.otherType0 = _BlockType.CODE_SINGLE;
})();
BlockType.SINGLE_TYPES = [_BlockType.DOLLAR_SINGLE, _BlockType.CODE_SINGLE];
function getLatexBlockType(editor, cursorPos, triggerInCodeBlocks) {
var _a;
const frontMatterBounds = (_a = getFrontMatterBounds(editor)) != null ? _a : { startLine: -1, endLine: -1 };
const blockTypeStack = [];
for (let lineIndex = Math.max(0, cursorPos.line - 1e3); lineIndex <= cursorPos.line; lineIndex++) {
if (lineIndex >= frontMatterBounds.startLine && lineIndex <= frontMatterBounds.endLine)
continue;
const line = editor.getLine(lineIndex);
for (let j = cursorPos.line == lineIndex ? cursorPos.ch - 1 : line.length - 1; j >= 0; j--) {
const currentChar = line.charAt(j);
let matchingBlockType = BlockType.SINGLE_TYPES.find((b) => b.c.charAt(0) === currentChar);
if (!matchingBlockType || line.charAt(Math.max(0, j - 1)) === "\\")
continue;
const multiTypeLength = matchingBlockType.otherType.c.length;
const isDouble = j + 1 >= multiTypeLength && substringMatches(line, matchingBlockType.otherType.c, j - multiTypeLength + 1);
if (isDouble) {
j -= multiTypeLength - 1;
matchingBlockType = matchingBlockType.otherType;
}
blockTypeStack.push({ type: matchingBlockType, line: lineIndex });
}
}
if (blockTypeStack.length < 1)
return null;
let currentIndex = 0;
while (true) {
if (currentIndex >= blockTypeStack.length)
return null;
const currentBlock = blockTypeStack[currentIndex];
const otherBlockIndex = findIndex(blockTypeStack, ({ type }) => type === currentBlock.type, currentIndex + 1);
if (otherBlockIndex === -1) {
if (!triggerInCodeBlocks && currentBlock.type.isCodeBlock)
return null;
if (currentBlock.type.isCodeBlock || currentBlock.type === BlockType.DOLLAR_SINGLE && currentBlock.line !== cursorPos.line) {
currentIndex++;
continue;
}
return currentBlock.type;
} else {
currentIndex = otherBlockIndex + 1;
}
}
}
function findIndex(arr, predicate, fromIndex) {
for (let i = fromIndex; i < arr.length; i++) {
if (predicate(arr[i]))
return i;
}
return -1;
}
function substringMatches(str, toMatch, from) {
for (let i = from; i < from + toMatch.length - 1; i++) {
if (str.charAt(i) !== toMatch.charAt(i - from))
return false;
}
return true;
}
// src/marker_state_field.ts
var import_state = require("@codemirror/state");
var import_view = require("@codemirror/view");
var addMark = import_state.StateEffect.define();
var clearMarks = import_state.StateEffect.define();
var removeMarkBySpecAttribute = import_state.StateEffect.define();
var markerStateField = import_state.StateField.define({
create() {
return import_view.Decoration.none;
},
update(value, tr) {
value = value.map(tr.changes);
for (let effect of tr.effects) {
if (effect.is(addMark))
value = value.update({ add: [effect.value] });
else if (effect.is(clearMarks))
value = value.update({ filter: () => false });
else if (effect.is(removeMarkBySpecAttribute))
value = value.update({ filter: (from, to, ref) => ref.spec[effect.value.attribute] !== effect.value[effect.value.attribute] });
}
return value;
},
provide: (f) => import_view.EditorView.decorations.from(f)
});
// src/snippet_manager.ts
var COLORS = ["lightskyblue", "orange", "lime", "pink", "cornsilk", "magenta", "navajowhite"];
var PlaceholderReference = class {
constructor(editor) {
this.editor = editor;
}
get marker() {
const state = editorToCodeMirrorState(this.editor);
const iter = state.field(markerStateField).iter();
while (iter.value) {
if (iter.value.spec.reference === this) {
return {
from: iter.from,
to: iter.to,
value: iter.value
};
}
iter.next();
}
return null;
}
removeFromEditor() {
editorToCodeMirrorView(this.editor).dispatch({
effects: removeMarkBySpecAttribute.of({ attribute: "reference", reference: this })
});
}
};
var SnippetManager = class {
constructor() {
this.currentPlaceholderReferences = [];
}
handleSnippet(value, start, editor) {
let colorIndex = 0;
for (; colorIndex < COLORS.length; colorIndex++) {
if (!this.currentPlaceholderReferences.find((p) => p.marker.value.spec.attributes.class.endsWith(colorIndex + "")))
break;
}
if (colorIndex === COLORS.length) {
console.log("Completr: No colors left for snippet, using random color");
colorIndex = Math.floor(Math.random() * COLORS.length);
}
const editorView = editorToCodeMirrorView(editor);
const lines = value.split("\n");
for (let lineIndex = lines.length - 1; lineIndex >= 0; lineIndex--) {
const line = lines[lineIndex];
for (let i = line.length - 1; i >= 0; i--) {
const c = line.charAt(i);
if (c !== "#" && c !== "~")
continue;
const lineBaseOffset = lineIndex === 0 ? start.ch : 0;
if (c === "~") {
const cursorPos = { line: start.line + lineIndex, ch: lineBaseOffset + i };
editor.setCursor(cursorPos);
editor.replaceRange("", cursorPos, __spreadProps(__spreadValues({}, cursorPos), { ch: cursorPos.ch + 1 }));
continue;
}
const reference = new PlaceholderReference(editor);
let mark = import_view2.Decoration.mark({
inclusive: true,
attributes: {
style: "border-width: 1px 0 1px 0;border-style: solid;",
class: "completr-suggestion-placeholder" + colorIndex
},
reference
}).range(
indexFromPos(editorView.state.doc, { line: start.line + lineIndex, ch: lineBaseOffset + i }),
indexFromPos(editorView.state.doc, { line: start.line + lineIndex, ch: lineBaseOffset + i + 1 })
);
editorView.dispatch({ effects: addMark.of(mark) });
this.currentPlaceholderReferences.unshift(reference);
}
}
this.selectMarker(this.currentPlaceholderReferences[0]);
}
consumeAndGotoNextMarker(editor) {
const oldPlaceholder = this.currentPlaceholderReferences.shift();
const oldRange = SnippetManager.rangeFromPlaceholder(oldPlaceholder);
oldPlaceholder.removeFromEditor();
if (this.currentPlaceholderReferences.length === 0)
return false;
const placeholder = this.currentPlaceholderReferences[0];
const newRange = SnippetManager.rangeFromPlaceholder(placeholder);
if (!newRange)
return false;
if (newRange.from.ch <= oldRange.from.ch && newRange.to.ch >= oldRange.to.ch) {
editor.setCursor(__spreadValues({}, newRange.to));
} else {
this.selectMarker(placeholder);
}
return true;
}
placeholderAtPos(pos) {
for (let i = this.currentPlaceholderReferences.length - 1; i >= 0; i--) {
const placeholder = this.currentPlaceholderReferences[i];
const range = SnippetManager.rangeFromPlaceholder(placeholder);
if (!range) {
this.currentPlaceholderReferences.slice(i, 1);
continue;
}
if (range.from.ch <= pos.ch && range.to.ch >= pos.ch)
return placeholder;
}
return null;
}
selectMarker(reference) {
if (!reference)
return;
const from = posFromIndex(editorToCodeMirrorState(reference.editor).doc, reference.marker.from);
reference.editor.setSelection(from, __spreadProps(__spreadValues({}, from), { ch: from.ch + 1 }));
}
clearAllPlaceholders() {
if (this.currentPlaceholderReferences.length === 0)
return;
const firstRef = this.currentPlaceholderReferences[0];
const view = editorToCodeMirrorView(firstRef.editor);
view.dispatch({
effects: clearMarks.of(null)
});
this.currentPlaceholderReferences = [];
}
static rangeFromPlaceholder(reference) {
const marker = reference.marker;
if (!marker)
return null;
return {
from: posFromIndex(editorToCodeMirrorState(reference.editor).doc, marker.from),
to: posFromIndex(editorToCodeMirrorState(reference.editor).doc, marker.to)
};
}
onunload() {
this.clearAllPlaceholders();
}
};
// src/provider/provider.ts
function getSuggestionDisplayName(suggestion, lowerCase = false) {
const res = typeof suggestion === "string" ? suggestion : suggestion.displayName;
return maybeLowerCase(res, lowerCase);
}
function getSuggestionReplacement(suggestion) {
return typeof suggestion === "string" ? suggestion : suggestion.replacement;
}
// src/provider/latex_provider.ts
var import_obsidian = require("obsidian");
// src/provider/blacklist.ts
var BLACKLIST_PATH = ".obsidian/plugins/obsidian-completr/blacklisted_suggestions.txt";
var NEW_LINE_REGEX = /\r?\n/;
var SuggestionBlacklist = new class {
constructor() {
this.blacklist = /* @__PURE__ */ new Set();
}
add(suggestion) {
this.blacklist.add(getSuggestionDisplayName(suggestion));
}
has(suggestion) {
return this.blacklist.has(getSuggestionDisplayName(suggestion));
}
filter(suggestions) {
if (this.blacklist.size < 1)
return suggestions;
return suggestions.filter((s) => !this.blacklist.has(getSuggestionDisplayName(s)));
}
saveData(vault) {
return __async(this, null, function* () {
yield vault.adapter.write(BLACKLIST_PATH, [...this.blacklist].join("\n"));
});
}
loadData(vault) {
return __async(this, null, function* () {
if (!(yield vault.adapter.exists(BLACKLIST_PATH)))
return;
const contents = (yield vault.adapter.read(BLACKLIST_PATH)).split(NEW_LINE_REGEX);
for (let word of contents) {
if (!word)
continue;
this.add(word);
}
});
}
}();
// src/provider/latex_provider.ts
function substringUntil(str, delimiter) {
let index = str.indexOf(delimiter);
if (index === -1)
return str;
return str.substring(0, index);
}
var LATEX_COMMANDS_PATH = ".obsidian/plugins/obsidian-completr/latex_commands.json";
var LatexSuggestionProvider = class {
constructor() {
this.loadedCommands = [];
}
getSuggestions(context, settings) {
if (!settings.latexProviderEnabled || !context.query || context.query.length < settings.latexMinWordTriggerLength)
return [];
let editor = context.editor;
const latexBlockType = getLatexBlockType(editor, context.start, settings.latexTriggerInCodeBlocks);
const isSingleBlock = latexBlockType === BlockType.DOLLAR_SINGLE;
if (!latexBlockType)
return [];
const query = maybeLowerCase(context.query, settings.latexIgnoreCase);
const isSeparatorBackslash = context.separatorChar === "\\";
return this.loadedCommands.filter((s) => getSuggestionDisplayName(s, settings.latexIgnoreCase).contains(query)).map((s) => {
let replacement = getSuggestionReplacement(s);
replacement = isSeparatorBackslash ? replacement.substring(1) : replacement;
replacement = isSingleBlock ? replacement.replace(/\n/g, "") : replacement;
return {
displayName: getSuggestionDisplayName(s),
replacement,
priority: getSuggestionDisplayName(s, settings.latexIgnoreCase).indexOf(query)
};
}).sort((a, b) => {
let val = a.priority - b.priority;
if (val == 0)
val = substringUntil(a.displayName, "{").length - substringUntil(b.displayName, "{").length;
return val;
});
}
loadCommands(vault) {
return __async(this, null, function* () {
if (!(yield vault.adapter.exists(LATEX_COMMANDS_PATH))) {
const defaultCommands = generateDefaultLatexCommands();
yield vault.adapter.write(LATEX_COMMANDS_PATH, JSON.stringify(defaultCommands, null, 2));
this.loadedCommands = defaultCommands;
} else {
const data = yield vault.adapter.read(LATEX_COMMANDS_PATH);
try {
const commands = JSON.parse(data);
const invalidCommand = commands.find((c) => getSuggestionDisplayName(c).includes("\n"));
if (invalidCommand)
throw new Error("Display name cannot contain a newline: " + getSuggestionDisplayName(invalidCommand));
this.loadedCommands = commands;
} catch (e) {
console.log("Completr latex commands parse error:", e.message);
new import_obsidian.Notice("Failed to parse latex commands file " + LATEX_COMMANDS_PATH + ". Using default commands.", 3e3);
this.loadedCommands = generateDefaultLatexCommands();
}
}
this.loadedCommands = SuggestionBlacklist.filter(this.loadedCommands);
});
}
};
var Latex = new LatexSuggestionProvider();
function generateEnvironments(environments) {
const result = [];
for (let i = 0; i < environments.length; i++) {
const environment = environments[i];
if (environment.hasStarVersion) {
environments.push(__spreadProps(__spreadValues({}, environment), { name: environment.name + "*", hasStarVersion: false }));
}
result.push({
displayName: `\\begin{${environment.name}}...`,
replacement: `\\begin{${environment.name}}${"{#}".repeat(environment.paramCount)}
${environment.paramCount < 1 ? "~\n" : ""}\\end{${environment.name}}`
});
}
return result;
}
function generateDefaultLatexCommands() {
return [
...generateEnvironments([
{ name: "align", paramCount: 0, hasStarVersion: true },
{ name: "alignat", paramCount: 1, hasStarVersion: true },
{ name: "aligned", paramCount: 0, hasStarVersion: false },
{ name: "alignedat", paramCount: 1, hasStarVersion: false },
{ name: "array", paramCount: 1, hasStarVersion: false },
{ name: "bmatrix", paramCount: 0, hasStarVersion: true },
{ name: "Bmatrix", paramCount: 0, hasStarVersion: true },
{ name: "bsmallmatrix", paramCount: 0, hasStarVersion: true },
{ name: "Bsmallmatrix", paramCount: 0, hasStarVersion: true },
{ name: "cases", paramCount: 0, hasStarVersion: true },
{ name: "crampedsubarray", paramCount: 1, hasStarVersion: false },
{ name: "dcases", paramCount: 0, hasStarVersion: true },
{ name: "drcases", paramCount: 0, hasStarVersion: true },
{ name: "empheq", paramCount: 2, hasStarVersion: false },
{ name: "eqnarray", paramCount: 0, hasStarVersion: true },
{ name: "equation", paramCount: 0, hasStarVersion: true },
{ name: "flalign", paramCount: 0, hasStarVersion: true },
{ name: "gather", paramCount: 0, hasStarVersion: true },
{ name: "gathered", paramCount: 0, hasStarVersion: false },
{ name: "lgathered", paramCount: 0, hasStarVersion: false },
{ name: "matrix", paramCount: 0, hasStarVersion: true },
{ name: "multiline", paramCount: 0, hasStarVersion: true },
{ name: "multilined", paramCount: 0, hasStarVersion: false },
{ name: "numcases", paramCount: 1, hasStarVersion: false },
{ name: "pmatrix", paramCount: 0, hasStarVersion: true },
{ name: "prooftree", paramCount: 0, hasStarVersion: false },
{ name: "psmallmatrix", paramCount: 0, hasStarVersion: true },
{ name: "rcases", paramCount: 0, hasStarVersion: true },
{ name: "rgathered", paramCount: 0, hasStarVersion: false },
{ name: "smallmatrix", paramCount: 0, hasStarVersion: true },
{ name: "split", paramCount: 0, hasStarVersion: false },
{ name: "spreadlines", paramCount: 1, hasStarVersion: false },
{ name: "subarray", paramCount: 1, hasStarVersion: false },
{ name: "subnumcases", paramCount: 1, hasStarVersion: false },
{ name: "vmatrix", paramCount: 0, hasStarVersion: true },
{ name: "Vmatrix", paramCount: 0, hasStarVersion: true },
{ name: "vsmallmatrix", paramCount: 0, hasStarVersion: true },
{ name: "Vsmallmatrix", paramCount: 0, hasStarVersion: true },
{ name: "xalignat", paramCount: 1, hasStarVersion: true },
{ name: "xxalignat", paramCount: 1, hasStarVersion: false }
]),
"\\above{#}{#}",
"\\verb|#|",
"\\left\\",
"\\right\\",
"\\acute{#}",
"\\aleph",
"\\alpha",
"\\amalg",
"\\And",
"\\angle",
"\\approx",
"\\approxeq",
"\\arccos",
"\\arcsin",
"\\arctan",
"\\arg",
"\\array{#}",
"\\arrowvert",
"\\Arrowvert",
"\\ast",
"\\asymp",
"\\atop",
"\\backepsilon",
"\\backprime",
"\\backsim",
"\\backsimeq",
"\\backslash",
"\\bar{#}",
"\\barwedge",
"\\Bbb{#}",
"\\Bbbk",
"\\bbFont",
"\\bbox{#}",
"\\bcancel{#}",
"\\because",
"\\beta",
"\\beth",
"\\between",
"\\bf",
"\\bigcap",
"\\bigcirc",
"\\bigcup",
"\\bigodot",
"\\bigoplus",
"\\bigotimes",
"\\bigsqcup",
"\\bigstar",
"\\bigtimes",
"\\bigtriangledown",
"\\bigtriangleup",
"\\biguplus",
"\\bigvee",
"\\bigwedge",
"\\binom{#}{#}",
"\\blacklozenge",
"\\blacksquare",
"\\blacktriangle",
"\\blacktriangledown",
"\\blacktriangleleft",
"\\blacktriangleright",
"\\bmod",
"\\boldsymbol{#}",
"\\bot",
"\\bowtie",
"\\Box",
"\\boxdot",
"\\boxed{#}",
"\\boxminus",
"\\boxplus",
"\\boxtimes",
"\\bra{#}",
"\\Bra{#}",
"\\brace",
"\\bracevert",
"\\brack",
"\\braket{#}",
"\\Braket{#}",
"\\breve{#}",
"\\bullet",
"\\bumpeq",
"\\Bumpeq",
"\\cal",
"\\cancel{#}",
"\\cancelto{#}{#}",
"\\cap",
"\\Cap",
"\\cases{#}",
"\\cdot",
"\\cdotp",
"\\cdots",
"\\celsius",
"\\centercolon",
"\\centerdot",
"\\centernot{#}",
"\\centerOver{#}{#}",
"\\cfrac{#}{#}",
"\\check{#}",
"\\checkmark",
"\\chi",
"\\choose",
"\\circ",
"\\circeq",
"\\circlearrowleft",
"\\circlearrowright",
"\\circledast",
"\\circledcirc",
"\\circleddash",
"\\circledR",
"\\circledS",
"\\clap{#}",
"\\class{#}{#}",
"\\clubsuit",
"\\colon",
"\\colonapprox",
"\\Colonapprox",
"\\coloneq",
"\\Coloneq",
"\\coloneqq",
"\\Coloneqq",
"\\colonsim",
"\\Colonsim",
"\\color{#}",
"\\colorbox{#}{#}",
"\\complement",
"\\cong",
"\\coprod",
"\\cos",
"\\cosh",
"\\cot",
"\\coth",
"\\cramped{#}",
"\\crampedclap{#}",
"\\crampedllap{#}",
"\\crampedrlap{#}",
"\\crampedsubstack{#}",
"\\csc",
"\\cssId{#}{#}",
"\\cup",
"\\Cup",
"\\curlyeqprec",
"\\curlyeqsucc",
"\\curlyvee",
"\\curlywedge",
"\\curvearrowleft",
"\\curvearrowright",
"\\dagger",
"\\daleth",
"\\dashleftarrow",
"\\dashrightarrow",
"\\dashv",
"\\dbinom{#}{#}",
"\\dblcolon",
"\\ddagger",
"\\ddddot{#}",
"\\dddot{#}",
"\\ddot{#}",
"\\ddots",
"\\DeclareMathOperator{#}{#}",
"\\DeclarePairedDelimiters{#}{#}{#}",
"\\DeclarePairedDelimitersX{#}{#}{#}{#}",
"\\DeclarePairedDelimitersXPP{#}{#}{#}{#}{#}{#}",
"\\deg",
"\\degree",
"\\delta",
"\\Delta",
"\\det",
"\\dfrac{#}{#}",
"\\diagdown",
"\\diagup",
"\\diamond",
"\\Diamond",
"\\diamondsuit",
"\\digamma",
"\\dim",
"\\displaylines{#}",
"\\displaystyle",
"\\div",
"\\divideontimes",
"\\divsymbol",
"\\dot{#}",
"\\doteq",
"\\Doteq",
"\\doteqdot",
"\\dotplus",
"\\dots",
"\\dotsb",
"\\dotsc",
"\\dotsi",
"\\dotsm",
"\\dotso",
"\\doublebarwedge",
"\\doublecap",
"\\doublecup",
"\\downarrow",
"\\Downarrow",
"\\downdownarrows",
"\\downharpoonleft",
"\\downharpoonright",
"\\ell",
"\\empheqbiglangle",
"\\empheqbiglbrace",
"\\empheqbiglbrack",
"\\empheqbiglceil",
"\\empheqbiglfloor",
"\\empheqbiglparen",
"\\empheqbiglvert",
"\\empheqbiglVert",
"\\empheqbigrangle",
"\\empheqbigrbrace",
"\\empheqbigrbrack",
"\\empheqbigrceil",
"\\empheqbigrfloor",
"\\empheqbigrparen",
"\\empheqbigrvert",
"\\empheqbigrVert",
"\\empheqlangle",
"\\empheqlbrace",
"\\empheqlbrack",
"\\empheqlceil",
"\\empheqlfloor",
"\\empheqlparen",
"\\empheqlvert",
"\\empheqlVert",
"\\empheqrangle",
"\\empheqrbrace",
"\\empheqrbrack",
"\\empheqrceil",
"\\empheqrfloor",
"\\empheqrparen",
"\\empheqrvert",
"\\empheqrVert",
"\\emptyset",
"\\enclose{#}{#}",
"\\enspace",
"\\epsilon",
"\\eqalign{#}",
"\\eqalignno{#}",
"\\eqcirc",
"\\eqcolon",
"\\Eqcolon",
"\\eqqcolon",
"\\Eqqcolon",
"\\eqref{#}",
"\\eqsim",
"\\eqslantgtr",
"\\eqslantless",
"\\equiv",
"\\eta",
"\\eth",
"\\exists",
"\\exp",
"\\fallingdotseq",
"\\fbox{#}",
"\\fCenter",
"\\fcolorbox{#}{#}{#}",
"\\Finv",
"\\flat",
"\\forall",
"\\frac{#}{#}",
"\\frak",
"\\framebox{#}",
"\\frown",
"\\Game",
"\\gamma",
"\\Gamma",
"\\gcd",
"\\ge",
"\\geq",
"\\geqq",
"\\geqslant",
"\\gets",
"\\gg",
"\\ggg",
"\\gggtr",
"\\gimel",
"\\gnapprox",
"\\gneq",
"\\gneqq",
"\\gnsim",
"\\grave{#}",
"\\gt",
"\\gtrapprox",
"\\gtrdot",
"\\gtreqless",
"\\gtreqqless",
"\\gtrless",
"\\gtrsim",
"\\gvertneqq",
"\\hat{#}",
"\\hbar",
"\\hbox{#}",
"\\heartsuit",
"\\hline",
"\\hom",
"\\hookleftarrow",
"\\hookrightarrow",
"\\hphantom{#}",
"\\href{#}{#}",
"\\hslash",
"\\huge",
"\\Huge",
"\\idotsint",
"\\iff",
"\\iiiint",
"\\iiint",
"\\iint",
"\\Im",
"\\imath",
"\\impliedby",
"\\implies",
"\\in",
"\\inf",
"\\infty",
"\\injlim",
"\\int",
"\\int^{#}_{#}",
"\\intercal",
"\\intop",
"\\iota",
"\\it",
"\\jmath",
"\\Join",
"\\kappa",
"\\ker",
"\\ket{#}",
"\\Ket{#}",
"\\ketbra{#}{#}",
"\\Ketbra{#}{#}",
"\\label{#}",
"\\lambda",
"\\Lambda",
"\\land",
"\\langle",
"\\large",
"\\Large",
"\\LARGE",
"\\LaTeX",
"\\lbrace",
"\\lbrack",
"\\lceil",
"\\ldots",
"\\ldotp",
"\\le",
"\\leadsto",
"\\Leftarrow",
"\\leftarrow",
"\\leftarrowtail",
"\\leftharpoondown",
"\\leftharpoonup",
"\\leftleftarrows",
"\\Leftrightarrow",
"\\leftrightarrow",
"\\leftrightarrows",
"\\leftrightharpoons",
"\\leftrightsquigarrow",
"\\leftthreetimes",
"\\leq",
"\\leqalignno{#}",
"\\leqq",
"\\leqslant",
"\\lessapprox",
"\\lessdot",
"\\lesseqgtr",
"\\lesseqqgtr",
"\\lessgtr",
"\\lesssim",
"\\lfloor",
"\\lg",
"\\lgroup",
"\\lhd",
"\\lim",
"\\lim_{#}",
"\\liminf",
"\\limsup",
"\\ll",
"\\llap{#}",
"\\llcorner",
"\\Lleftarrow",
"\\lll",
"\\llless",
"\\lmoustache",
"\\ln",
"\\lnapprox",
"\\lneq",
"\\lneqq",
"\\lnot",
"\\lnsim",
"\\log",
"\\longleftarrow",
"\\Longleftarrow",
"\\Longleftrightarrow",
"\\longleftrightarrow",
"\\longleftrightarrows",
"\\longLeftrightharpoons",
"\\longmapsto",
"\\longrightarrow",
"\\Longrightarrow",
"\\longrightleftharpoons",
"\\longRightleftharpoons",
"\\looparrowleft",
"\\looparrowright",
"\\lor",
"\\lozenge",
"\\lparen",
"\\lrcorner",
"\\Lsh",
"\\lt",
"\\ltimes",
"\\lvert",
"\\lVert",
"\\lvertneqq",
"\\maltese",
"\\mapsto",
"\\mathbb{#}",
"\\mathbb{R}",
"\\mathbb{N}",
"\\mathbb{C}",
"\\mathbb{Z}",
"\\mathbb{Q}",
"\\mathbf{#}",
"\\mathbfcal{#}",
"\\mathbffrak{#}",
"\\mathbfit{#}",
"\\mathbfscr{#}",
"\\mathbfsf{#}",
"\\mathbfsfit{#}",
"\\mathbfsfup{#}",
"\\mathbfup{#}",
"\\mathbin{#}",
"\\mathcal{#}",
"\\mathchoice{#}{#}{#}{#}",
"\\mathclap{#}",
"\\mathclose{#}",
"\\mathfrak{#}",
"\\mathinner{#}",
"\\mathit{#}",
"\\mathllap{#}",
"\\mathmakebox{#}",
"\\mathmbox{#}",
"\\mathnormal{#}",
"\\mathop{#}",
"\\mathopen{#}",
"\\mathord{#}",
"\\mathpunct{#}",
"\\mathrel{#}",
"\\mathring{#}",
"\\mathrlap{#}",
"\\mathrm{#}",
"\\mathscr{#}",
"\\mathsf{#}",
"\\mathsfit{#}",
"\\mathsfup{#}",
"\\mathstrut",
"\\mathtip{#}{#}",
"\\mathtt{#}",
"\\mathup{#}",
"\\max",
"\\mbox{#}",
"\\measuredangle",
"\\mho",
"\\micro",
"\\mid",
"\\min",
"\\mit",
"\\mod{#}",
"\\models",
"\\mp",
"\\MTThinColon",
"\\mu",
"\\multimap",
"\\nabla",
"\\natural",
"\\ncong",
"\\ndownarrow",
"\\ne",
"\\nearrow",
"\\neg",
"\\negmedspace",
"\\negthickspace",
"\\negthinspace",
"\\neq",
"\\newcommand{#}{#}",
"\\newenvironment{#}{#}{#}",
"\\newline",
"\\newtagform{#}{#}{#}",
"\\nexists",
"\\ngeq",
"\\ngeqq",
"\\ngeqslant",
"\\ngtr",
"\\ni",
"\\nleftarrow",
"\\nLeftarrow",
"\\nleftrightarrow",
"\\nLeftrightarrow",
"\\nleq",
"\\nleqq",
"\\nleqslant",
"\\nless",
"\\nmid",
"\\nobreakspace",
"\\nonscript",
"\\nonumber",
"\\normalsize",
"\\not",
"\\notag",
"\\notChar",
"\\notin",
"\\nparallel",
"\\nprec",
"\\npreceq",
"\\nrightarrow",
"\\nRightarrow",
"\\nshortmid",
"\\nshortparallel",
"\\nsim",
"\\nsubseteq",
"\\nsubseteqq",
"\\nsucc",
"\\nsucceq",
"\\nsupseteq",
"\\nsupseteqq",
"\\ntriangleleft",
"\\ntrianglelefteq",
"\\ntriangleright",
"\\ntrianglerighteq",
"\\nu",
"\\nuparrow",
"\\nvdash",
"\\nvDash",
"\\nVdash",
"\\nVDash",
"\\nwarrow",
"\\odot",
"\\ohm",
"\\oint",
"\\oldstyle",
"\\omega",
"\\Omega",
"\\omicron",
"\\ominus",
"\\operatorname{#}",
"\\oplus",
"\\ordinarycolon",
"\\oslash",
"\\otimes",
"\\over",
"\\overbrace{#}",
"\\overbracket{#}",
"\\overleftarrow{#}",
"\\overleftrightarrow{#}",
"\\overline{#}",
"\\overparen{#}",
"\\overrightarrow{#}",
"\\overset{#}{#}",
"\\overunderset{#}{#}{#}",
"\\owns",
"\\parallel",
"\\partial",
"\\perp",
"\\perthousand",
"\\phantom{#}",
"\\phi",
"\\Phi",
"\\pi",
"\\Pi",
"\\pitchfork",
"\\pm",
"\\pmb{#}",
"\\pmod{#}",
"\\pod{#}",
"\\Pr",
"\\prec",
"\\precapprox",
"\\preccurlyeq",
"\\preceq",
"\\precnapprox",
"\\precneqq",
"\\precnsim",
"\\precsim",
"\\prescript{#}{#}{#}",
"\\prime",
"\\prod",
"\\prod^{#}_{#}",
"\\projlim",
"\\propto",
"\\psi",
"\\Psi",
"\\qquad",
"\\quad",
"\\rangle",
"\\rbrace",
"\\rbrack",
"\\rceil",
"\\Re",
"\\ref{#}",
"\\refeq{#}",
"\\renewcommand{#}{#}",
"\\renewenvironment{#}{#}{#}",
"\\renewtagform{#}{#}{#}",
"\\restriction",
"\\rfloor",
"\\rgroup",
"\\rhd",
"\\rho",
"\\Rightarrow",
"\\rightarrow",
"\\rightarrowtail",
"\\rightharpoondown",
"\\rightharpoonup",
"\\rightleftarrows",
"\\rightleftharpoons",
"\\rightrightarrows",
"\\rightsquigarrow",
"\\rightthreetimes",
"\\risingdotseq",
"\\rlap{#}",
"\\rm",
"\\rmoustache",
"\\rparen",
"\\Rrightarrow",
"\\Rsh",
"\\rtimes",
"\\rvert",
"\\rVert",
"\\S",
"\\scr",
"\\scriptscriptstyle",
"\\scriptsize",
"\\scriptstyle",
"\\searrow",
"\\sec",
"\\set{#}",
"\\Set{#}",
"\\setminus",
"\\sf",
"\\sharp",
"\\shortmid",
"\\shortparallel",
"\\sideset{#}{#}{#}",
"\\sigma",
"\\Sigma",
"\\sim",
"\\simeq",
"\\sin",
"\\sinh",
"\\skew{#}{#}{#}",
"\\SkipLimits",
"\\small",
"\\smallfrown",
"\\smallint",
"\\smallsetminus",
"\\smallsmile",
"\\smash{#}",
"\\smile",
"\\space",
"\\spadesuit",
"\\sphericalangle",
"\\splitdfrac{#}{#}",
"\\splitfrac{#}{#}",
"\\sqcap",
"\\sqcup",
"\\sqrt{#}",
"\\sqsubset",
"\\sqsubseteq",
"\\sqsupset",
"\\sqsupseteq",
"\\square",
"\\stackbin{#}{#}",
"\\stackrel{#}{#}",
"\\star",
"\\strut",
"\\style{#}{#}",
"\\subset",
"\\Subset",
"\\subseteq",
"\\subseteqq",
"\\subsetneq",
"\\subsetneqq",
"\\substack{#}",
"\\succ",
"\\succapprox",
"\\succcurlyeq",
"\\succeq",
"\\succnapprox",
"\\succneqq",
"\\succnsim",
"\\succsim",
"\\sum",
"\\sum^{#}_{#}",
"\\sup",
"\\supset",
"\\Supset",
"\\supseteq",
"\\supseteqq",
"\\supsetneq",
"\\supsetneqq",
"\\surd",
"\\swarrow",
"\\symbb{#}",
"\\symbf{#}",
"\\symbfcal{#}",
"\\symbffrak{#}",
"\\symbfit{#}",
"\\symbfscr{#}",
"\\symbfsf{#}",
"\\symbfsfit{#}",
"\\symbfsfup{#}",
"\\symbfup{#}",
"\\symcal{#}",
"\\symfrak{#}",
"\\symit{#}",
"\\symnormal{#}",
"\\symrm{#}",
"\\symscr{#}",
"\\symsf{#}",
"\\symsfit{#}",
"\\symsfup{#}",
"\\symtt{#}",
"\\symup{#}",
"\\tag{#}",
"\\tan",
"\\tanh",
"\\tau",
"\\tbinom{#}{#}",
"\\TeX",
"\\text{#}",
"\\textacutedbl",
"\\textasciiacute",
"\\textasciibreve",
"\\textasciicaron",
"\\textasciicircum",
"\\textasciidieresis",
"\\textasciimacron",
"\\textasciitilde",
"\\textasteriskcentered",
"\\textbackslash",
"\\textbaht",
"\\textbar",
"\\textbardbl",
"\\textbf{#}",
"\\textbigcircle",
"\\textblank",
"\\textborn",
"\\textbraceleft",
"\\textbraceright",
"\\textbrokenbar",
"\\textbullet",
"\\textcelsius",
"\\textcent",
"\\textcentoldstyle",
"\\textcircledP",
"\\textclap{#}",
"\\textcolonmonetary",
"\\textcolor{#}{#}",
"\\textcompwordmark",
"\\textcopyleft",
"\\textcopyright",
"\\textcurrency",
"\\textdagger",
"\\textdaggerdbl",
"\\textdegree",
"\\textdied",
"\\textdiscount",
"\\textdiv",
"\\textdivorced",
"\\textdollar",
"\\textdollaroldstyle",
"\\textdong",
"\\textdownarrow",
"\\texteightoldstyle",
"\\textellipsis",
"\\textemdash",
"\\textendash",
"\\textestimated",
"\\texteuro",
"\\textexclamdown",
"\\textfiveoldstyle",
"\\textflorin",
"\\textfouroldstyle",
"\\textfractionsolidus",
"\\textgravedbl",
"\\textgreater",
"\\textguarani",
"\\textinterrobang",
"\\textinterrobangdown",
"\\textit{#}",
"\\textlangle",
"\\textlbrackdbl",
"\\textleftarrow",
"\\textless",
"\\textlira",
"\\textllap{#}",
"\\textlnot",
"\\textlquill",
"\\textmarried",
"\\textmho",
"\\textminus",
"\\textmu",
"\\textmusicalnote",
"\\textnaira",
"\\textnineoldstyle",
"\\textnormal{#}",
"\\textnumero",
"\\textohm",
"\\textonehalf",
"\\textoneoldstyle",
"\\textonequarter",
"\\textonesuperior",
"\\textopenbullet",
"\\textordfeminine",
"\\textordmasculine",
"\\textparagraph",
"\\textperiodcentered",
"\\textpertenthousand",
"\\textperthousand",
"\\textpeso",
"\\textpm",
"\\textquestiondown",
"\\textquotedblleft",
"\\textquotedblright",
"\\textquoteleft",
"\\textquoteright",
"\\textrangle",
"\\textrbrackdbl",
"\\textrecipe",
"\\textreferencemark",
"\\textregistered",
"\\textrightarrow",
"\\textrlap{#}",
"\\textrm{#}",
"\\textrquill",
"\\textsection",
"\\textservicemark",
"\\textsevenoldstyle",
"\\textsf{#}",
"\\textsixoldstyle",
"\\textsterling",
"\\textstyle",
"\\textsurd",
"\\textthreeoldstyle",
"\\textthreequarters",
"\\textthreesuperior",
"\\texttildelow",
"\\texttimes",
"\\texttip{#}{#}",
"\\texttrademark",
"\\texttt{#}",
"\\texttwooldstyle",
"\\texttwosuperior",
"\\textunderscore",
"\\textup{#}",
"\\textuparrow",
"\\textvisiblespace",
"\\textwon",
"\\textyen",
"\\textzerooldstyle",
"\\tfrac{#}{#}",
"\\therefore",
"\\theta",
"\\Theta",
"\\thickapprox",
"\\thicksim",
"\\thinspace",
"\\tilde{#}",
"\\times",
"\\tiny",
"\\Tiny",
"\\to",
"\\top",
"\\triangle",
"\\triangledown",
"\\triangleleft",
"\\trianglelefteq",
"\\triangleq",
"\\triangleright",
"\\trianglerighteq",
"\\tripledash",
"\\tt",
"\\twoheadleftarrow",
"\\twoheadrightarrow",
"\\ulcorner",
"\\underbrace{#}",
"\\underbracket{#}",
"\\underleftarrow{#}",
"\\underleftrightarrow{#}",
"\\underline{#}",
"\\underparen{#}",
"\\underrightarrow{#}",
"\\underset{#}{#}",
"\\unicode{#}",
"\\unlhd",
"\\unrhd",
"\\upalpha",
"\\uparrow",
"\\Uparrow",
"\\upbeta",
"\\upchi",
"\\updelta",
"\\Updelta",
"\\updownarrow",
"\\Updownarrow",
"\\upepsilon",
"\\upeta",
"\\upgamma",
"\\Upgamma",
"\\upharpoonleft",
"\\upharpoonright",
"\\upiota",
"\\upkappa",
"\\uplambda",
"\\Uplambda",
"\\uplus",
"\\upmu",
"\\upnu",
"\\upomega",
"\\Upomega",
"\\upomicron",
"\\upphi",
"\\Upphi",
"\\uppi",
"\\Uppi",
"\\uppsi",
"\\Uppsi",
"\\uprho",
"\\upsigma",
"\\Upsigma",
"\\upsilon",
"\\Upsilon",
"\\uptau",
"\\uptheta",
"\\Uptheta",
"\\upuparrows",
"\\upupsilon",
"\\Upupsilon",
"\\upvarepsilon",
"\\upvarphi",
"\\upvarpi",
"\\upvarrho",
"\\upvarsigma",
"\\upvartheta",
"\\upxi",
"\\Upxi",
"\\upzeta",
"\\urcorner",
"\\usetagform{#}",
"\\varDelta",
"\\varepsilon",
"\\varGamma",
"\\varinjlim",
"\\varkappa",
"\\varLambda",
"\\varliminf",
"\\varlimsup",
"\\varnothing",
"\\varOmega",
"\\varphi",
"\\varPhi",
"\\varpi",
"\\varPi",
"\\varprojlim",
"\\varpropto",
"\\varPsi",
"\\varrho",
"\\varsigma",
"\\varSigma",
"\\varsubsetneq",
"\\varsubsetneqq",
"\\varsupsetneq",
"\\varsupsetneqq",
"\\vartheta",
"\\varTheta",
"\\vartriangle",
"\\vartriangleleft",
"\\vartriangleright",
"\\varUpsilon",
"\\varXi",
"\\vcenter{#}",
"\\vdash",
"\\vDash",
"\\Vdash",
"\\vdots",
"\\vec{#}",
"\\vee",
"\\veebar",
"\\Vert",
"\\vert",
"\\vphantom{#}",
"\\Vvdash",
"\\wedge",
"\\widehat{#}",
"\\widetilde{#}",
"\\wp",
"\\wr",
"\\xcancel{#}",
"\\xhookleftarrow{#}",
"\\xhookrightarrow{#}",
"\\xi",
"\\Xi",
"\\xleftarrow{#}",
"\\xLeftarrow{#}",
"\\xleftharpoondown{#}",
"\\xleftharpoonup{#}",
"\\xleftrightarrow{#}",
"\\xLeftrightarrow{#}",
"\\xleftrightharpoons{#}",
"\\xLeftrightharpoons{#}",
"\\xlongequal{#}",
"\\xmapsto{#}",
"\\xmathstrut{#}",
"\\xrightarrow{#}",
"\\xRightarrow{#}",
"\\xrightharpoondown{#}",
"\\xrightharpoonup{#}",
"\\xrightleftharpoons{#}",
"\\xRightleftharpoons{#}",
"\\xtofrom{#}",
"\\xtwoheadleftarrow{#}",
"\\xtwoheadrightarrow{#}",
"\\yen",
"\\zeta"
];
}
// src/settings.ts
var DEFAULT_SETTINGS = {
characterRegex: "a-zA-Z\xF6\xE4\xFC\xD6\xC4\xDC\xDF",
maxLookBackDistance: 50,
minWordLength: 2,
minWordTriggerLength: 3,
wordInsertionMode: "Ignore-Case & Replace" /* IGNORE_CASE_REPLACE */,
ignoreDiacriticsWhenFiltering: false,
latexProviderEnabled: true,
latexTriggerInCodeBlocks: true,
latexMinWordTriggerLength: 2,
latexIgnoreCase: false,
fileScannerProviderEnabled: true,
fileScannerScanCurrent: true,
wordListProviderEnabled: true,
frontMatterProviderEnabled: true,
frontMatterTagAppendSuffix: true,
frontMatterIgnoreCase: true
};
// src/provider/dictionary_provider.ts
var DictionaryProvider = class {
getSuggestions(context, settings) {
var _a, _b, _c;
if (!this.isEnabled(settings) || !context.query || context.query.length < settings.minWordTriggerLength)
return [];
const ignoreCase = settings.wordInsertionMode != "Match-Case & Replace" /* MATCH_CASE_REPLACE */;
let query = maybeLowerCase(context.query, ignoreCase);
const ignoreDiacritics = settings.ignoreDiacriticsWhenFiltering;
if (ignoreDiacritics)
query = removeDiacritics(query);
const firstChar = query.charAt(0);
const list = ignoreCase ? [(_a = this.wordMap.get(firstChar)) != null ? _a : [], (_b = this.wordMap.get(firstChar.toUpperCase())) != null ? _b : []] : [(_c = this.wordMap.get(firstChar)) != null ? _c : []];
if (ignoreDiacritics) {
for (let [key, value] of this.wordMap.entries()) {
let keyFirstChar = maybeLowerCase(key.charAt(0), ignoreCase);
if (removeDiacritics(keyFirstChar) === firstChar)
list.push(value);
}
}
if (!list || list.length < 1)
return [];
const result = /* @__PURE__ */ new Set();
for (let el of list) {
filterMapIntoSet(
result,
el,
(s) => {
let match = maybeLowerCase(s, ignoreCase);
if (ignoreDiacritics)
match = removeDiacritics(match);
return match.startsWith(query);
},
settings.wordInsertionMode === "Ignore-Case & Append" /* IGNORE_CASE_APPEND */ ? (s) => context.query + s.substring(query.length, s.length) : (s) => s
);
}
return [...result].sort((a, b) => a.length - b.length);
}
};
var DIACRITICS_REGEX = /[\u0300-\u036f]/g;
function removeDiacritics(str) {
return str.normalize("NFD").replace(DIACRITICS_REGEX, "");
}
function filterMapIntoSet(set, iterable, predicate, map) {
for (let val of iterable) {
if (!predicate(val))
continue;
set.add(map(val));
}
}
// src/provider/word_list_provider.ts
var BASE_FOLDER_PATH = ".obsidian/plugins/obsidian-completr/wordLists";
var NEW_LINE_REGEX2 = /\r?\n/;
var WordListSuggestionProvider = class extends DictionaryProvider {
constructor() {
super(...arguments);
this.wordMap = /* @__PURE__ */ new Map();
}
isEnabled(settings) {
return settings.wordListProviderEnabled;
}
loadFromFiles(vault, settings) {
return __async(this, null, function* () {
this.wordMap.clear();
const fileNames = yield this.getRelativeFilePaths(vault);
for (let i = fileNames.length - 1; i >= 0; i--) {
const fileName = fileNames[i];
let data;
try {
data = yield vault.adapter.read(fileName);
} catch (e) {
console.log("Completr: Unable to read " + fileName);
continue;
}
const lines = data.split(NEW_LINE_REGEX2);
for (let line of lines) {
if (line === "" || line.length < settings.minWordLength)
continue;
let list = this.wordMap.get(line.charAt(0));
if (!list) {
list = [];
this.wordMap.set(line.charAt(0), list);
}
list.push(line.trim());
}
}
let count = 0;
for (let entry of this.wordMap.entries()) {
const newValue = SuggestionBlacklist.filter(entry[1].sort((a, b) => a.length - b.length));
this.wordMap.set(entry[0], newValue);
count += newValue.length;
}
return count;
});
}
deleteWordList(vault, path) {
return __async(this, null, function* () {
yield vault.adapter.remove(path);
});
}
importWordList(vault, name, text) {
return __async(this, null, function* () {
const path = BASE_FOLDER_PATH + "/" + name;
if (yield vault.adapter.exists(path))
return false;
yield vault.adapter.write(path, text);
return true;
});
}
getRelativeFilePaths(vault) {
return __async(this, null, function* () {
if (!(yield vault.adapter.exists(BASE_FOLDER_PATH)))
yield vault.adapter.mkdir(BASE_FOLDER_PATH);
return (yield vault.adapter.list(BASE_FOLDER_PATH)).files;
});
}
};
var WordList = new WordListSuggestionProvider();
// src/provider/scanner_provider.ts
var SCANNED_WORDS_PATH = ".obsidian/plugins/obsidian-completr/scanned_words.txt";
var NEW_LINE_REGEX3 = /\r?\n/;
var ScannerSuggestionProvider = class extends DictionaryProvider {
constructor() {
super(...arguments);
this.wordMap = /* @__PURE__ */ new Map();
}
isEnabled(settings) {
return settings.fileScannerProviderEnabled;
}
scanFiles(settings, files) {
return __async(this, null, function* () {
for (let file of files) {
yield this.scanFile(settings, file, false);
}
yield this.saveData(files[0].vault);
});
}
scanFile(settings, file, saveImmediately) {
return __async(this, null, function* () {
const contents = yield file.vault.cachedRead(file);
const regex = new RegExp("\\$+.*?\\$+|`+.*?`+|\\[+.*?\\]+|([" + settings.characterRegex + "]+)", "gsu");
for (let match of contents.matchAll(regex)) {
const groupValue = match[1];
if (!groupValue || groupValue.length < settings.minWordLength)
continue;
this.addWord(groupValue);
}
if (saveImmediately)
yield this.saveData(file.vault);
});
}
saveData(vault) {
return __async(this, null, function* () {
let output = [];
for (let entry of this.wordMap.entries()) {
output = [...output, ...entry[1]];
}
yield vault.adapter.write(SCANNED_WORDS_PATH, output.join("\n"));
});
}
loadData(vault) {
return __async(this, null, function* () {
if (!(yield vault.adapter.exists(SCANNED_WORDS_PATH)))
return;
const contents = (yield vault.adapter.read(SCANNED_WORDS_PATH)).split(NEW_LINE_REGEX3);
for (let word of contents) {
this.addWord(word);
}
});
}
deleteAllWords(vault) {
return __async(this, null, function* () {
this.wordMap.clear();
yield this.saveData(vault);
});
}
addWord(word) {
if (!word || SuggestionBlacklist.has(word))
return;
let list = this.wordMap.get(word.charAt(0));
if (!list) {
list = /* @__PURE__ */ new Set();
this.wordMap.set(word.charAt(0), list);
}
list.add(word);
}
};
var FileScanner = new ScannerSuggestionProvider();
// src/popup.ts
var import_obsidian3 = require("obsidian");
// src/provider/front_matter_provider.ts
var import_obsidian2 = require("obsidian");
var BASE_SUGGESTION = {
displayName: "front-matter",
replacement: "---\n~\n---",
overrideStart: { line: 0, ch: 0 }
};
var PUBLISH_SUGGESTION = {
displayName: "publish: #",
replacement: "publish: ~"
};
function findTagCompletionType(keyInfo, editor, currentLineIndex, currentLine, ignoreCase) {
const key = maybeLowerCase(keyInfo.key, ignoreCase);
const isList = keyInfo.isList;
if (currentLine.startsWith(key + ": "))
return "inline";
if (!currentLine.startsWith("- ") || !isList)
return "none";
let foundListStart = false;
for (let i = currentLineIndex - 1; i >= 1; i--) {
let line = editor.getLine(i).trim();
if (line.endsWith(":")) {
foundListStart = line.startsWith(key + ":");
break;
}
}
return foundListStart ? "multiline" : "none";
}
var YAMLKeyInfo = class {
constructor(key) {
this.key = key;
this.completions = /* @__PURE__ */ new Set();
}
addCompletion(value) {
this.completions.add(value);
}
};
var YAMLKeyCache = class {
constructor() {
this.keyMap = /* @__PURE__ */ new Map();
}
addEntry(key, value) {
let info = this.keyMap.get(key);
if (!info)
this.keyMap.set(key, info = new YAMLKeyInfo(key));
info.addCompletion(value);
}
addEntries(key, values) {
let info = this.keyMap.get(key);
if (!info)
this.keyMap.set(key, info = new YAMLKeyInfo(key));
for (let value of values) {
if (!value)
continue;
info.addCompletion(value);
}
info.isList = true;
}
getCompletions() {
return this.keyMap.values();
}
};
var FrontMatterSuggestionProvider = class {
constructor() {
this.blocksAllOtherProviders = true;
this.fileSuggestionCache = /* @__PURE__ */ new Map();
this.onCacheChange = (file, data, cache) => {
this.addKeyCompletionsFromFile(file, cache);
};
}
getSuggestions(context, settings) {
var _a;
if (!settings.frontMatterProviderEnabled)
return [];
const firstLine = context.editor.getLine(0);
const isInFrontMatter = isInFrontMatterBlock(context.editor, context.start);
const ignoreCase = settings.frontMatterIgnoreCase;
if (!isInFrontMatter && context.start.line === 0 && (firstLine === "" || "front-matter".startsWith(maybeLowerCase(firstLine, ignoreCase)))) {
return [BASE_SUGGESTION];
} else if (!isInFrontMatter) {
return [];
}
const query = maybeLowerCase(context.query, ignoreCase);
if (context.start.ch === 0) {
const suggestions = this.getPossibleCompletions().flatMap((i) => {
if (!i.isList) {
return [{
displayName: i.key + ": #",
replacement: i.key + ": ~"
}];
}
return [
{
displayName: i.key + ": [#]",
replacement: i.key + ": [~]"
},
{
displayName: i.key + ": \\...",
replacement: i.key + ":\n- ~"
}
];
});
suggestions.push(PUBLISH_SUGGESTION);
return suggestions.filter((snippet) => {
const displayName = getSuggestionDisplayName(snippet, ignoreCase);
const key2 = displayName.substring(0, displayName.indexOf(":"));
return key2.startsWith(query);
});
}
const currentLine = maybeLowerCase(context.editor.getLine(context.start.line), ignoreCase);
if (currentLine.startsWith("publish:"))
return FrontMatterSuggestionProvider.getPublishSuggestions(query);
const { key, type } = (_a = this.getPossibleCompletions().map((possibleKey) => ({
key: possibleKey,
type: findTagCompletionType(possibleKey, context.editor, context.start.line, currentLine, ignoreCase)
})).filter(({ type: type2 }) => type2 !== "none").shift()) != null ? _a : {};
if (!key)
return [];
const customQuery = maybeLowerCase(matchWordBackwards(
context.editor,
context.end,
(char) => new RegExp("[" + settings.characterRegex + "/\\-_]", "u").test(char),
settings.maxLookBackDistance
).query, ignoreCase);
return [...key.completions].filter((tag) => maybeLowerCase(tag, ignoreCase).startsWith(customQuery)).map((tag) => ({
displayName: tag,
replacement: tag + (settings.frontMatterTagAppendSuffix && key.isList ? type === "inline" ? ", " : "\n- " : ""),
overrideStart: __spreadProps(__spreadValues({}, context.end), { ch: context.end.ch - customQuery.length })
})).sort((a, b) => a.displayName.length - b.displayName.length);
}
loadYAMLKeyCompletions(cache, files) {
for (let file of files) {
this.addKeyCompletionsFromFile(file, cache.getFileCache(file));
}
}
addKeyCompletionsFromFile(file, cache) {
if (!file || !cache || !cache.frontmatter) {
return;
}
const keyCache = new YAMLKeyCache();
this.fileSuggestionCache.set(file.path, keyCache);
for (let key of Object.keys(cache.frontmatter)) {
if (key === "position" || key === "publish" || key === "tags")
continue;
let prop = cache.frontmatter[key];
if (!prop)
continue;
if (Array.isArray(prop)) {
keyCache.addEntries(key, prop);
} else {
keyCache.addEntry(key, prop);
}
}
const tags = (0, import_obsidian2.getAllTags)(cache);
if (tags && tags.length > 0)
keyCache.addEntries("tags", tags.map((t) => t.substring(1)));
}
getPossibleCompletions() {
const allKeys = /* @__PURE__ */ new Map();
for (let cache of this.fileSuggestionCache.values()) {
for (let keyInfo of cache.getCompletions()) {
let combinedKeyInfo = allKeys.get(keyInfo.key);
if (!combinedKeyInfo)
allKeys.set(keyInfo.key, combinedKeyInfo = new YAMLKeyInfo(keyInfo.key));
keyInfo.completions.forEach((c) => combinedKeyInfo.addCompletion(c));
combinedKeyInfo.isList = combinedKeyInfo.isList || keyInfo.isList;
}
}
return [...allKeys.values()];
}
static getPublishSuggestions(query) {
const possibilities = ["true", "false"];
const partialMatches = possibilities.filter((val) => val.startsWith(query) && val !== query);
if (partialMatches.length > 0)
return partialMatches;
else if (query === "true" || query === "false")
return query === "true" ? possibilities.reverse() : possibilities;
return [];
}
};
var FrontMatter = new FrontMatterSuggestionProvider();
// src/popup.ts
var PROVIDERS = [FrontMatter, Latex, FileScanner, WordList];
var SuggestionPopup = class extends import_obsidian3.EditorSuggest {
constructor(app, settings, snippetManager) {
var _a;
super(app);
this.disableSnippets = (_a = app.vault.config) == null ? void 0 : _a.legacyEditor;
this.settings = settings;
this.snippetManager = snippetManager;
let self = this;
self.scope.keys = [];
}
getSuggestions(context) {
let suggestions = [];
for (let provider of PROVIDERS) {
suggestions = [...suggestions, ...provider.getSuggestions(__spreadProps(__spreadValues({}, context), {
separatorChar: this.separatorChar
}), this.settings)];
if (provider.blocksAllOtherProviders && suggestions.length > 0) {
suggestions.forEach((suggestion) => {
if (typeof suggestion === "string" || !suggestion.overrideStart)
return;
this.context.start = suggestion.overrideStart;
});
break;
}
}
return suggestions.length === 0 ? null : suggestions.filter((s) => !SuggestionBlacklist.has(s));
}
onTrigger(cursor, editor, file) {
if (this.justClosed) {
this.justClosed = false;
return null;
}
let {
query,
separatorChar
} = matchWordBackwards(editor, cursor, (char) => this.getCharacterRegex().test(char), this.settings.maxLookBackDistance);
this.separatorChar = separatorChar;
return {
start: __spreadProps(__spreadValues({}, cursor), {
ch: cursor.ch - query.length
}),
end: cursor,
query
};
}
renderSuggestion(value, el) {
el.addClass("completr-suggestion-item");
el.setText(getSuggestionDisplayName(value));
}
selectSuggestion(value, evt) {
const replacement = getSuggestionReplacement(value);
const start = typeof value !== "string" && value.overrideStart ? value.overrideStart : this.context.start;
const endPos = this.context.end;
this.context.editor.replaceRange(replacement, start, __spreadProps(__spreadValues({}, endPos), {
ch: Math.min(endPos.ch, this.context.editor.getLine(endPos.line).length)
}));
if (replacement.contains("#") || replacement.contains("~")) {
if (!this.disableSnippets) {
this.snippetManager.handleSnippet(replacement, start, this.context.editor);
} else {
console.log("Completr: Please enable Live Preview mode to use snippets");
}
} else {
this.context.editor.setCursor(__spreadProps(__spreadValues({}, start), { ch: start.ch + replacement.length }));
}
this.close();
this.justClosed = true;
}
selectNextItem(dir) {
const self = this;
self.suggestions.setSelectedItem(self.suggestions.selectedItem + dir, new KeyboardEvent("keydown"));
}
getSelectedItem() {
const self = this;
return self.suggestions.values[self.suggestions.selectedItem];
}
applySelectedItem() {
const self = this;
self.suggestions.useSelectedItem();
}
isVisible() {
return this.isOpen;
}
preventNextTrigger() {
this.justClosed = true;
}
getCharacterRegex() {
if (this.characterRegex !== this.settings.characterRegex)
this.compiledCharacterRegex = new RegExp("[" + this.settings.characterRegex + "]", "u");
return this.compiledCharacterRegex;
}
};
// src/settings_tab.ts
var import_obsidian4 = require("obsidian");
var CompletrSettingsTab = class extends import_obsidian4.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.plugin = plugin;
}
display() {
const { containerEl } = this;
containerEl.empty();
new import_obsidian4.Setting(containerEl).setName("Word character regex").setDesc("A regular expression which matches a character of a word. Used by during completion to find the word to the left of the cursor and used by the file scanner to find valid words.").addText((text) => text.setValue(this.plugin.settings.characterRegex).onChange((val) => __async(this, null, function* () {
try {
new RegExp("[" + val + "]+").test("");
text.inputEl.removeClass("completr-settings-error");
this.plugin.settings.characterRegex = val;
yield this.plugin.saveSettings();
} catch (e) {
text.inputEl.addClass("completr-settings-error");
}
})));
new import_obsidian4.Setting(containerEl).setName("Minimum word length").setDesc("The minimum length a word has to be, to count as a valid suggestion. This value is used by the file scanner and word list provider.").addText((text) => {
text.inputEl.type = "number";
text.setValue(this.plugin.settings.minWordLength + "").onChange((val) => __async(this, null, function* () {
if (!val || val.length < 1)
return;
this.plugin.settings.minWordLength = parseInt(val);
yield this.plugin.saveSettings();
}));
});
new import_obsidian4.Setting(containerEl).setName("Minimum word trigger length").setDesc("The minimum length a word has to be, to trigger suggestions. The LaTeX provider has its own separate setting.").addText((text) => {
text.inputEl.type = "number";
text.setValue(this.plugin.settings.minWordTriggerLength + "").onChange((val) => __async(this, null, function* () {
if (!val || val.length < 1)
return;
this.plugin.settings.minWordTriggerLength = parseInt(val);
yield this.plugin.saveSettings();
}));
});
new import_obsidian4.Setting(containerEl).setName("Word insertion mode").setDesc("The insertion mode that is used. Ignore-case would suggest 'Hello' if the typed text is 'hello', match-case would not. Append would complete 'Hell' with 'Hello' while replace would complete it with 'hello' instead (if only 'hello' was a known word). Only used by the file scanner and word list provider.").addDropdown(
(dropdown) => dropdown.addOption("Ignore-Case & Replace" /* IGNORE_CASE_REPLACE */, "Ignore-Case & Replace" /* IGNORE_CASE_REPLACE */).addOption("Ignore-Case & Append" /* IGNORE_CASE_APPEND */, "Ignore-Case & Append" /* IGNORE_CASE_APPEND */).addOption("Match-Case & Replace" /* MATCH_CASE_REPLACE */, "Match-Case & Replace" /* MATCH_CASE_REPLACE */).setValue(this.plugin.settings.wordInsertionMode).onChange((val) => __async(this, null, function* () {
this.plugin.settings.wordInsertionMode = val;
yield this.plugin.saveSettings();
}))
);
new import_obsidian4.Setting(containerEl).setName("Ignore diacritics when filtering").setDesc("When enabled, the query 'Hello' can suggest 'H\xE8ll\xF2', meaning diacritics will be ignored when filtering the suggestions. Only used by the file scanner and word list provider.").addToggle((toggle) => toggle.setValue(this.plugin.settings.ignoreDiacriticsWhenFiltering).onChange((val) => __async(this, null, function* () {
this.plugin.settings.ignoreDiacriticsWhenFiltering = val;
yield this.plugin.saveSettings();
})));
new import_obsidian4.Setting(containerEl).setName("Latex provider").setHeading();
this.createEnabledSetting("latexProviderEnabled", "Whether or not the latex provider is enabled", containerEl);
new import_obsidian4.Setting(containerEl).setName("Trigger in code blocks").setDesc("Whether the LaTeX provider should trigger after dollar signs which are enclosed in code blocks (for example ```$\\fr```).").addToggle((toggle) => toggle.setValue(this.plugin.settings.latexTriggerInCodeBlocks).onChange((val) => __async(this, null, function* () {
this.plugin.settings.latexTriggerInCodeBlocks = val;
yield this.plugin.saveSettings();
})));
new import_obsidian4.Setting(containerEl).setName("Ignore case").setDesc("Whether the LaTeX provider should ignore the casing of the typed text. If so, the input 'MaThbb' could suggest 'mathbb'.").addToggle((toggle) => toggle.setValue(this.plugin.settings.latexIgnoreCase).onChange((val) => __async(this, null, function* () {
this.plugin.settings.latexIgnoreCase = val;
yield this.plugin.saveSettings();
})));
new import_obsidian4.Setting(containerEl).setName("Minimum word trigger length").setDesc("The minimum length a query has to be, to trigger suggestions.").addText((text) => {
text.inputEl.type = "number";
text.setValue(this.plugin.settings.latexMinWordTriggerLength + "").onChange((val) => __async(this, null, function* () {
if (!val || val.length < 1)
return;
this.plugin.settings.latexMinWordTriggerLength = parseInt(val);
yield this.plugin.saveSettings();
}));
});
new import_obsidian4.Setting(containerEl).setName("Front matter provider").addExtraButton((button) => button.setIcon("link").setTooltip("Obsidian Front-Matter wiki").onClick(() => window.open("https://help.obsidian.md/Advanced+topics/YAML+front+matter"))).setHeading();
this.createEnabledSetting("frontMatterProviderEnabled", "Whether the front matter provider is enabled", containerEl);
new import_obsidian4.Setting(containerEl).setName("Ignore case").setDesc("Whether the Front matter provider should ignore the casing of the typed text. If so, the input 'MaThbb' could suggest 'mathbb'.").addToggle((toggle) => toggle.setValue(this.plugin.settings.frontMatterIgnoreCase).onChange((val) => __async(this, null, function* () {
this.plugin.settings.frontMatterIgnoreCase = val;
yield this.plugin.saveSettings();
})));
new import_obsidian4.Setting(containerEl).setName("Add suffix to tag completion").setDesc("Whether each completed tag should be suffixed with a comma or a newline (when typing in a multi-line list). Allows faster insertion of multiple tags.").addToggle((toggle) => toggle.setValue(this.plugin.settings.frontMatterTagAppendSuffix).onChange((val) => __async(this, null, function* () {
this.plugin.settings.frontMatterTagAppendSuffix = val;
yield this.plugin.saveSettings();
})));
new import_obsidian4.Setting(containerEl).setName("File scanner provider").setHeading().addExtraButton((button) => button.setIcon("search").setTooltip("Immediately scan all .md files currently in your vault.").onClick(() => {
new ConfirmationModal(
this.plugin.app,
"Start scanning?",
"Depending on the size of your vault and computer, this may take a while.",
(button2) => button2.setButtonText("Scan").setCta(),
() => __async(this, null, function* () {
yield FileScanner.scanFiles(this.plugin.settings, this.plugin.app.vault.getMarkdownFiles());
})
).open();
})).addExtraButton((button) => button.setIcon("trash").setTooltip("Delete all known words.").onClick(() => __async(this, null, function* () {
new ConfirmationModal(
this.plugin.app,
"Delete all known words?",
"This will delete all words that have been scanned. No suggestions from this provider will show up anymore until new files are scanned.",
(button2) => button2.setButtonText("Delete").setWarning(),
() => __async(this, null, function* () {
yield FileScanner.deleteAllWords(this.plugin.app.vault);
})
).open();
})));
this.createEnabledSetting("fileScannerProviderEnabled", "Whether or not the file scanner provider is enabled.", containerEl);
new import_obsidian4.Setting(containerEl).setName("Scan active file").setDesc("If this setting is enabled, the currently opened file will be scanned to find new words.").addToggle((toggle) => toggle.setValue(this.plugin.settings.fileScannerScanCurrent).onChange((val) => __async(this, null, function* () {
this.plugin.settings.fileScannerScanCurrent = val;
yield this.plugin.saveSettings();
})));
new import_obsidian4.Setting(containerEl).setName("Word list provider").setHeading();
this.createEnabledSetting("wordListProviderEnabled", "Whether or not the word list provider is enabled", containerEl);
const fileInput = createEl("input", {
attr: {
type: "file"
}
});
fileInput.onchange = () => __async(this, null, function* () {
const files = fileInput.files;
if (files.length < 1)
return;
let changed = false;
for (let i = 0; i < files.length; i++) {
const file = files[i];
const text = yield file.text();
const success = yield WordList.importWordList(this.app.vault, file.name, text);
changed || (changed = success);
if (!success)
new import_obsidian4.Notice("Unable to import " + file.name + " because it already exists!");
}
if (!changed)
return;
yield this.reloadWords();
this.display();
});
new import_obsidian4.Setting(containerEl).setName("Word list files").setDesc("A list of files which contain words to be used as suggestions. Each word should be on its own line.").addExtraButton((button) => button.setIcon("switch").setTooltip("Reload").onClick(() => __async(this, null, function* () {
yield this.reloadWords();
this.display();
}))).addButton((button) => {
button.buttonEl.appendChild(fileInput);
button.setButtonText("+").setCta().onClick(() => fileInput.click());
});
const wordListDiv = containerEl.createDiv();
WordList.getRelativeFilePaths(this.app.vault).then((names) => {
for (const name of names) {
new import_obsidian4.Setting(wordListDiv).setName(name).addExtraButton(
(button) => button.setIcon("trash").setTooltip("Remove").onClick(() => __async(this, null, function* () {
new ConfirmationModal(
this.app,
"Delete " + name + "?",
"The file will be removed and the words inside of it won't show up as suggestions anymore.",
(button2) => button2.setButtonText("Delete").setWarning(),
() => __async(this, null, function* () {
yield WordList.deleteWordList(this.app.vault, name);
yield this.reloadWords();
this.display();
})
).open();
}))
).settingEl.addClass("completr-settings-list-item");
}
});
}
reloadWords() {
return __async(this, null, function* () {
if (this.isReloadingWords)
return;
this.isReloadingWords = true;
const count = yield WordList.loadFromFiles(this.app.vault, this.plugin.settings);
this.isReloadingWords = false;
new import_obsidian4.Notice(`Loaded ${count} words`);
});
}
createEnabledSetting(propertyName, desc, container) {
new import_obsidian4.Setting(container).setName("Enabled").setDesc(desc).addToggle((toggle) => toggle.setValue(this.plugin.settings[propertyName]).onChange((val) => __async(this, null, function* () {
this.plugin.settings[propertyName] = val;
yield this.plugin.saveSettings();
})));
}
};
var ConfirmationModal = class extends import_obsidian4.Modal {
constructor(app, title, body, buttonCallback, clickCallback) {
super(app);
this.titleEl.setText(title);
this.contentEl.setText(body);
new import_obsidian4.Setting(this.modalEl).addButton((button) => {
buttonCallback(button);
button.onClick(() => __async(this, null, function* () {
yield clickCallback();
this.close();
}));
}).addButton((button) => button.setButtonText("Cancel").onClick(() => this.close())).settingEl.addClass("completr-settings-no-border");
}
};
// src/main.ts
var import_view3 = require("@codemirror/view");
var CompletrPlugin = class extends import_obsidian5.Plugin {
constructor() {
super(...arguments);
this.onFileOpened = (file) => {
if (!this.settings.fileScannerScanCurrent || !file)
return;
FileScanner.scanFile(this.settings, file, true);
};
}
onload() {
return __async(this, null, function* () {
var _a;
yield this.loadSettings();
this.snippetManager = new SnippetManager();
this._suggestionPopup = new SuggestionPopup(this.app, this.settings, this.snippetManager);
this.registerEditorSuggest(this._suggestionPopup);
this.registerEvent(this.app.workspace.on("file-open", this.onFileOpened, this));
this.registerEvent(this.app.metadataCache.on("changed", FrontMatter.onCacheChange, FrontMatter));
this.app.workspace.onLayoutReady(() => FrontMatter.loadYAMLKeyCompletions(this.app.metadataCache, this.app.vault.getMarkdownFiles()));
this.registerEditorExtension(markerStateField);
this.registerEditorExtension(import_view3.EditorView.updateListener.of(new CursorActivityListener(this.snippetManager, this._suggestionPopup).listener));
this.addSettingTab(new CompletrSettingsTab(this.app, this));
this.setupCommands();
if ((_a = this.app.vault.config) == null ? void 0 : _a.legacyEditor) {
console.log("Completr: Without Live Preview enabled, most features of Completr will not work properly!");
}
});
}
setupCommands() {
const app = this.app;
app.scope.keys = [];
const isHotkeyMatch = (hotkey, context, id) => {
const modifiers = hotkey.modifiers, key = hotkey.key;
if (modifiers !== null && (id.contains("completr-bypass") ? !context.modifiers.contains(modifiers) : modifiers !== context.modifiers))
return false;
return !key || (key === context.vkey || !(!context.key || key.toLowerCase() !== context.key.toLowerCase()));
};
this.app.scope.register(null, null, (e, t) => {
const hotkeyManager = app.hotkeyManager;
hotkeyManager.bake();
for (let bakedHotkeys = hotkeyManager.bakedHotkeys, bakedIds = hotkeyManager.bakedIds, r = 0; r < bakedHotkeys.length; r++) {
const hotkey = bakedHotkeys[r];
const id = bakedIds[r];
if (isHotkeyMatch(hotkey, t, id)) {
const command = app.commands.findCommand(id);
if (!command || e.repeat && !command.repeatable) {
continue;
} else if (command.isVisible && !command.isVisible()) {
continue;
} else if (id.contains("completr-bypass")) {
this._suggestionPopup.close();
const validMods = t.modifiers.replace(new RegExp(`${hotkey.modifiers},*`), "").split(",");
let event = new KeyboardEvent("keydown", {
key: hotkeyManager.defaultKeys[id][0].key,
ctrlKey: validMods.contains("Ctrl"),
shiftKey: validMods.contains("Shift"),
altKey: validMods.contains("Alt"),
metaKey: validMods.contains("Meta")
});
e.target.dispatchEvent(event);
return false;
}
if (app.commands.executeCommandById(id))
return false;
}
}
});
this.addCommand({
id: "completr-open-suggestion-popup",
name: "Open suggestion popup",
hotkeys: [
{
key: " ",
modifiers: ["Mod"]
}
],
editorCallback: (editor) => {
this._suggestionPopup.trigger(editor, this.app.workspace.getActiveFile(), true);
}
});
this.addCommand({
id: "completr-select-next-suggestion",
name: "Select next suggestion",
hotkeys: [
{
key: "ArrowDown",
modifiers: []
}
],
repeatable: true,
editorCallback: (editor) => {
this.suggestionPopup.selectNextItem(1 /* NEXT */);
},
isVisible: () => this._suggestionPopup.isVisible()
});
this.addCommand({
id: "completr-select-previous-suggestion",
name: "Select previous suggestion",
hotkeys: [
{
key: "ArrowUp",
modifiers: []
}
],
repeatable: true,
editorCallback: (editor) => {
this.suggestionPopup.selectNextItem(-1 /* PREVIOUS */);
},
isVisible: () => this._suggestionPopup.isVisible()
});
this.addCommand({
id: "completr-insert-selected-suggestion",
name: "Insert selected suggestion",
hotkeys: [
{
key: "Enter",
modifiers: []
}
],
editorCallback: (editor) => {
this.suggestionPopup.applySelectedItem();
},
isVisible: () => this._suggestionPopup.isVisible()
});
this.addCommand({
id: "completr-bypass-enter-key",
name: "Bypass the popup and press Enter",
hotkeys: [
{
key: "Enter",
modifiers: ["Ctrl"]
}
],
editorCallback: (editor) => {
},
isVisible: () => this._suggestionPopup.isVisible()
});
this.addCommand({
id: "completr-bypass-tab-key",
name: "Bypass the popup and press Tab",
hotkeys: [
{
key: "Tab",
modifiers: ["Ctrl"]
}
],
editorCallback: (editor) => {
},
isVisible: () => this._suggestionPopup.isVisible()
});
this.addCommand({
id: "completr-blacklist-current-word",
name: "Add the currently selected word to the blacklist",
hotkeys: [
{
key: "D",
modifiers: ["Shift"]
}
],
editorCallback: (editor) => {
SuggestionBlacklist.add(this._suggestionPopup.getSelectedItem());
SuggestionBlacklist.saveData(this.app.vault);
this._suggestionPopup.trigger(editor, this.app.workspace.getActiveFile(), true);
},
isVisible: () => this._suggestionPopup.isVisible()
});
this.addCommand({
id: "completr-close-suggestion-popup",
name: "Close suggestion popup",
hotkeys: [
{
key: "Escape",
modifiers: []
}
],
editorCallback: (editor) => {
this.suggestionPopup.close();
},
isVisible: () => this._suggestionPopup.isVisible()
});
this.addCommand({
id: "completr-jump-to-next-snippet-placeholder",
name: "Jump to next snippet placeholder",
hotkeys: [
{
key: "Enter",
modifiers: []
}
],
editorCallback: (editor, view) => {
const placeholder = this.snippetManager.placeholderAtPos(editor.getCursor());
if (!placeholder)
return;
const placeholderEnd = posFromIndex(editorToCodeMirrorState(placeholder.editor).doc, placeholder.marker.to);
if (!this.snippetManager.consumeAndGotoNextMarker(editor)) {
editor.setSelections([{
anchor: __spreadProps(__spreadValues({}, placeholderEnd), {
ch: Math.min(editor.getLine(placeholderEnd.line).length, placeholderEnd.ch + 1)
})
}]);
}
},
isVisible: () => {
const view = this.app.workspace.getActiveViewOfType(import_obsidian5.MarkdownView);
if (!view)
return false;
const placeholder = this.snippetManager.placeholderAtPos(view.editor.getCursor());
return placeholder != null;
}
});
}
onunload() {
return __async(this, null, function* () {
this.snippetManager.onunload();
yield FileScanner.saveData(this.app.vault);
});
}
loadSettings() {
return __async(this, null, function* () {
this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData());
SuggestionBlacklist.loadData(this.app.vault).then(() => {
WordList.loadFromFiles(this.app.vault, this.settings);
FileScanner.loadData(this.app.vault);
Latex.loadCommands(this.app.vault);
});
});
}
get suggestionPopup() {
return this._suggestionPopup;
}
saveSettings() {
return __async(this, null, function* () {
yield this.saveData(this.settings);
});
}
};
var CursorActivityListener = class {
constructor(snippetManager, suggestionPopup) {
this.cursorTriggeredByChange = false;
this.lastCursorLine = -1;
this.listener = (update) => {
if (update.docChanged) {
this.handleDocChange();
}
if (update.selectionSet) {
this.handleCursorActivity(posFromIndex(update.state.doc, update.state.selection.main.head));
}
};
this.handleDocChange = () => {
this.cursorTriggeredByChange = true;
};
this.handleCursorActivity = (cursor) => {
if (this.lastCursorLine == cursor.line + 1)
this.suggestionPopup.preventNextTrigger();
this.lastCursorLine = cursor.line;
if (!this.snippetManager.placeholderAtPos(cursor)) {
this.snippetManager.clearAllPlaceholders();
}
if (this.cursorTriggeredByChange) {
this.cursorTriggeredByChange = false;
return;
}
this.suggestionPopup.close();
};
this.snippetManager = snippetManager;
this.suggestionPopup = suggestionPopup;
}
};