You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

802 lines
164 KiB

3 years ago
'use strict';
var obsidian = require('obsidian');
3 years ago
/******************************************************************************
3 years ago
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());
});
}
function getAllExpandersQuery(content) {
2 years ago
let accum = [];
3 years ago
for (var i = 0; i < content.length; i++) {
2 years ago
const line = content[i];
3 years ago
if (line === '```expander') {
for (var e = 0; e < content.length - i; e++) {
2 years ago
const nextline = content[i + e];
3 years ago
if (nextline === '```') {
accum.push({
start: i,
end: i + e,
query: content[i + 1],
template: e > 2 ? content.slice(i + 2, i + e).join('\n') : ''
});
break;
}
}
}
}
return accum;
}
function getClosestQuery(queries, lineNumber) {
if (queries.length === 0) {
return undefined;
}
2 years ago
return queries.reduce((a, b) => {
3 years ago
return Math.abs(b.start - lineNumber) < Math.abs(a.start - lineNumber) ? b : a;
});
}
function getLastLineToReplace(content, query, endline) {
2 years ago
const lineFrom = query.end;
3 years ago
for (var i = lineFrom + 1; i < content.length; i++) {
if (content[i] === endline) {
return i;
}
}
return lineFrom + 1;
}
2 years ago
const pick = (obj, arr) => arr.reduce((acc, curr) => {
return (curr in obj)
? Object.assign({}, acc, { [curr]: obj[curr] })
: acc;
}, {});
// Functions for string processing
function splitByLines(content) {
return content.split('\n');
}
function removeEmptyLines(s) {
const lines = s.split('\n').map(e => e.trim());
if (lines.length < 2) {
3 years ago
return s;
2 years ago
}
else if (lines.indexOf('') === 0) {
return removeEmptyLines(lines.slice(1).join('\n'));
}
return s;
}
function removeFrontMatter(s, lookEnding = false) {
const lines = s.split('\n');
if (lookEnding && lines.indexOf('---') === 0) {
return lines.slice(1).join('\n');
}
else if (lookEnding) {
return removeFrontMatter(lines.slice(1).join('\n'), true);
}
else if (lines.indexOf('---') === 0) {
return removeFrontMatter(lines.slice(1).join('\n'), true);
}
return s;
}
function trimContent(content) {
return removeFrontMatter(removeEmptyLines(content));
}
function getFrontMatter(file, plugin, s) {
const { frontmatter = null } = plugin.app.metadataCache.getCache(file.path);
if (frontmatter) {
return frontmatter[s.split(':')[1]] || '';
}
return '';
}
function getFileInfo(plugin, file) {
return __awaiter(this, void 0, void 0, function* () {
const info = Object.assign({}, file, {
content: file.extension === 'md' ? yield plugin.app.vault.cachedRead(file) : '',
link: plugin.app.fileManager.generateMarkdownLink(file, file.name).replace(/^!/, '')
}, plugin.app.metadataCache.getFileCache(file));
return pick(info, [
'basename',
'content',
'extension',
'headings',
'link', 'name',
'path', 'sections', 'stat',
'frontmatter',
'links',
'listItems'
]);
});
3 years ago
}
3 years ago
function highlight(lineStart, lineEnd, matchStart, matchEnd, lineContent) {
2 years ago
return [
...lineContent.slice(0, matchStart - lineStart),
'==',
...lineContent.slice(matchStart - lineStart, (matchStart - lineStart) + (matchEnd - matchStart)),
'==',
...lineContent.slice((matchStart - lineStart) + (matchEnd - matchStart)),
].join('');
3 years ago
}
2 years ago
const sequences = [
3 years ago
{
name: '\\$count',
loop: true,
2 years ago
format: (_p, _s, _content, _file, _d, index) => index ? String(index + 1) : String(1),
3 years ago
desc: 'add index number to each produced file'
},
{
name: '\\$filename',
loop: true,
2 years ago
format: (_p, _s, _content, file) => file.basename,
3 years ago
desc: 'name of the founded file'
},
{
name: '\\$link',
loop: true,
2 years ago
format: (p, _s, _content, file) => p.app.fileManager.generateMarkdownLink(file, file.path).replace('![[', '[['),
3 years ago
desc: 'link based on Obsidian settings'
},
{
name: '\\$lines:\\d+',
loop: true,
readContent: true,
2 years ago
format: (p, s, content, _file) => {
const digits = Number(s.split(':')[1]);
3 years ago
return trimContent(content)
.split('\n')
2 years ago
.filter((_, i) => i < digits)
3 years ago
.join('\n')
.replace(new RegExp(p.config.lineEnding, 'g'), '');
},
desc: 'specified count of lines from the found file'
},
{
name: '\\$characters:\\d+',
loop: true,
readContent: true,
2 years ago
format: (p, s, content, _file) => {
const digits = Number(s.split(':')[1]);
3 years ago
return trimContent(content)
.split('')
2 years ago
.filter((_, i) => i < digits)
3 years ago
.join('')
.replace(new RegExp(p.config.lineEnding, 'g'), '');
},
desc: 'specified count of lines from the found file'
},
{
name: '\\$frontmatter:[\\p\{L\}_-]+',
loop: true,
2 years ago
format: (p, s, _content, file) => getFrontMatter(file, p, s),
3 years ago
desc: 'value from the frontmatter key in the found file'
},
{
name: '\\$lines+',
loop: true,
readContent: true,
2 years ago
format: (p, s, content, _file) => content.replace(new RegExp(p.config.lineEnding, 'g'), ''),
3 years ago
desc: 'all content from the found file'
},
{
name: '\\$ext',
loop: true,
2 years ago
format: (_p, s, content, file) => file.extension,
3 years ago
desc: 'return file extension'
},
{
name: '\\$created:format:date',
loop: true,
2 years ago
format: (_p, s, content, file) => String(new Date(file.stat.ctime).toISOString()).split('T')[0],
3 years ago
desc: 'created time formatted'
},
{
name: '\\$created:format:time',
loop: true,
2 years ago
format: (_p, s, content, file) => String(new Date(file.stat.ctime).toISOString()).split(/([.T])/)[2],
3 years ago
desc: 'created time formatted'
},
{
name: '\\$created:format',
loop: true,
2 years ago
format: (_p, s, content, file) => String(new Date(file.stat.ctime).toISOString()),
3 years ago
desc: 'created time formatted'
},
{
name: '\\$created',
loop: true,
2 years ago
format: (_p, s, content, file) => String(file.stat.ctime),
3 years ago
desc: 'created time'
},
{
name: '\\$size',
loop: true,
2 years ago
format: (_p, s, content, file) => String(file.stat.size),
3 years ago
desc: 'size of the file'
},
{
name: '\\$path',
loop: true,
2 years ago
format: (_p, s, content, file) => file.path,
3 years ago
desc: 'path to the found file'
},
{
name: '\\$parent',
loop: true,
2 years ago
format: (_p, s, content, file) => file.parent.name,
3 years ago
desc: 'parent folder name'
},
{
name: '^(.+|)\\$header:.+',
loop: true,
2 years ago
format: (p, s, content, file) => {
3 years ago
var _a;
2 years ago
const prefix = s.slice(0, s.indexOf('$'));
const header = s.slice(s.indexOf('$')).replace('$header:', '').replace(/"/g, '');
const neededLevel = header.split("#").length - 1;
const neededTitle = header.replace(/^#+/g, '').trim();
const metadata = p.app.metadataCache.getFileCache(file);
return ((_a = metadata.headings) === null || _a === void 0 ? void 0 : _a.filter(e => {
const tests = [
3 years ago
[neededTitle, e.heading.includes(neededTitle)],
[neededLevel, e.level === neededLevel]
2 years ago
].filter(e => e[0]);
3 years ago
if (tests.length) {
2 years ago
return tests.map(e => e[1]).every(e => e === true);
3 years ago
}
return true;
2 years ago
}).map(h => p.app.fileManager.generateMarkdownLink(file, file.basename, '#' + h.heading)).map(link => prefix + link).join('\n')) || '';
3 years ago
},
desc: 'headings from founded files. $header:## - return all level 2 headings. $header:Title - return all heading which match the string. Can be prepended like: - !$header:## to transclude the headings.'
},
{
name: '^(.+|)\\$blocks',
readContent: true,
loop: true,
2 years ago
format: (p, s, content, file) => {
const prefix = s.slice(0, s.indexOf('$'));
3 years ago
return content
.split('\n')
2 years ago
.filter(e => /\^\w+$/.test(e))
.map(e => prefix + p.app.fileManager.generateMarkdownLink(file, file.basename, '#' + e.replace(/^.+?(\^\w+$)/, '$1')))
3 years ago
.join('\n');
},
desc: 'block ids from the found files. Can be prepended.'
},
{
2 years ago
name: '^(.+|)\\$match:header', loop: true, format: (p, s, content, file, results) => {
3 years ago
var _a;
2 years ago
const prefix = s.slice(0, s.indexOf('$'));
const metadata = p.app.metadataCache.getFileCache(file);
const headings = (_a = metadata.headings) === null || _a === void 0 ? void 0 : _a.filter(h => results.result.content.filter(c => h.position.end.offset < c[0]).some(e => e)).slice(-1);
3 years ago
return headings
2 years ago
.map(h => p.app.fileManager.generateMarkdownLink(file, file.basename, '#' + h.heading))
.map(link => prefix + link)
3 years ago
.join('\n') || '';
}, desc: 'extract found selections'
},
{
3 years ago
name: '^(.+|)\\$matchline(:(\\+|-|)\\d+:\\d+|:(\\+|-|)\\d+|)',
3 years ago
loop: true,
2 years ago
format: (_p, s, content, file, results) => {
const prefix = s.slice(0, s.indexOf('$matchline'));
const [keyword, context, limit] = s.slice(s.indexOf('$matchline')).split(':');
const value = context || '';
const limitValue = Number(limit);
const isPlus = value.contains('+');
const isMinus = value.contains('-');
const isContext = !isPlus && !isMinus;
const offset = Number(value.replace(/[+-]/, ''));
const lines = results.content.split('\n');
3 years ago
// Grab info about line content, index, text length and start/end character position
2 years ago
const lineInfos = [];
for (let i = 0; i < lines.length; i++) {
const text = lines[i];
3 years ago
if (i === 0) {
lineInfos.push({
num: 0,
start: 0,
end: text.length,
2 years ago
text
3 years ago
});
continue;
}
2 years ago
const start = lineInfos[i - 1].end + 1;
3 years ago
lineInfos.push({
num: i,
2 years ago
start,
text,
3 years ago
end: text.length + start
});
}
2 years ago
return results.result.content.map(([from, to]) => {
const matchedLines = lineInfos
.filter(({ start, end }) => start <= from && end >= to)
.map((line) => {
return Object.assign(Object.assign({}, line), { text: highlight(line.start, line.end, from, to, line.text) });
3 years ago
});
2 years ago
const resultLines = [];
for (const matchedLine of matchedLines) {
const prevLines = isMinus || isContext
? lineInfos.filter(l => matchedLine.num - l.num > 0 && matchedLine.num - l.num < offset)
3 years ago
: [];
2 years ago
const nextLines = isPlus || isContext
? lineInfos.filter(l => l.num - matchedLine.num > 0 && l.num - matchedLine.num < offset)
3 years ago
: [];
2 years ago
resultLines.push(...prevLines, matchedLine, ...nextLines);
3 years ago
}
2 years ago
return prefix + resultLines.map(e => e.text).join('\n');
}).map(line => limitValue ? line.slice(0, limitValue) : line).join('\n');
3 years ago
}, desc: 'extract line with matches'
},
{
3 years ago
name: '^(.+|)\\$searchresult',
loop: true,
desc: '',
2 years ago
format: (_p, s, content, file, results) => {
const prefix = s.slice(0, s.indexOf('$searchresult'));
return results.children.map(matchedFile => {
3 years ago
return prefix + matchedFile.el.innerText;
3 years ago
}).join('\n');
3 years ago
}
3 years ago
},
{
2 years ago
name: '^(.+|)\\$match', loop: true, format: (_p, s, content, file, results) => {
3 years ago
if (!results.result.content) {
console.warn('There is no content in results');
return '';
}
function appendPrefix(prefix, line) {
return prefix + line;
}
2 years ago
const prefixContent = s.slice(0, s.indexOf('$'));
3 years ago
return results.result.content
2 years ago
.map(([from, to]) => results.content.slice(from, to))
.map(line => appendPrefix(prefixContent, line))
3 years ago
.join('\n');
}, desc: 'extract found selections'
},
];
2 years ago
function extractFilesFromSearchResults(searchResults, currentFileName, excludeCurrent = true) {
const files = Array.from(searchResults.keys());
return excludeCurrent
? files.filter(file => file.basename !== currentFileName)
: files;
}
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function createCommonjsModule(fn, basedir, module) {
return module = {
path: basedir,
exports: {},
require: function (path, base) {
return commonjsRequire(path, (base === undefined || base === null) ? module.path : base);
}
}, fn(module, module.exports), module.exports;
}
function commonjsRequire () {
throw new Error('Dynamic requires are not currently supported by @rollup/plugin-commonjs');
}
var eta_min = createCommonjsModule(function (module, exports) {
!function(e,n){n(exports);}(commonjsGlobal,(function(e){function n(e){var t,r,i=new Error(e);return t=i,r=n.prototype,Object.setPrototypeOf?Object.setPrototypeOf(t,r):t.__proto__=r,i}function t(e,t,r){var i=t.slice(0,r).split(/\n/),a=i.length,o=i[a-1].length+1;throw n(e+=" at line "+a+" col "+o+":\n\n "+t.split(/\n/)[a-1]+"\n "+Array(o).join(" ")+"^")}n.prototype=Object.create(Error.prototype,{name:{value:"Eta Error",enumerable:!1}});var r=new Function("return this")().Promise;function i(e,n){for(var t in n)r=n,i=t,Object.prototype.hasOwnProperty.call(r,i)&&(e[t]=n[t]);var r,i;return e}function a(e,n,t,r){var i,a;return Array.isArray(n.autoTrim)?(i=n.autoTrim[1],a=n.autoTrim[0]):i=a=n.autoTrim,(t||!1===t)&&(i=t),(r||!1===r)&&(a=r),a||i?"slurp"===i&&"slurp"===a?e.trim():("_"===i||"slurp"===i?e=function(e){return String.prototype.trimLeft?e.trimLeft():e.replace(/^\s+/,"")}(e):"-"!==i&&"nl"!==i||(e=e.replace(/^(?:\r\n|\n|\r)/,"")),"_"===a||"slurp"===a?e=function(e){return String.prototype.trimRight?e.trimRight():e.replace(/\s+$/,"")}(e):"-"!==a&&"nl"!==a||(e=e.replace(/(?:\r\n|\n|\r)$/,"")),e):e}var o={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function c(e){return o[e]}var s=/`(?:\\[\s\S]|\${(?:[^{}]|{(?:[^{}]|{[^}]*})*})*}|(?!\${)[^\\`])*`/g,l=/'(?:\\[\s\w"'\\`]|[^\n\r'\\])*?'/g,u=/"(?:\\[\s\w"'\\`]|[^\n\r"\\])*?"/g;function p(e){return e.replace(/[.*+\-?^${}()|[\]\\]/g,"\\$&")}function f(e,n){var r=[],i=!1,o=0,c=n.parse;if(n.plugins)for(var f=0;f<n.plugins.length;f++){(T=n.plugins[f]).processTemplate&&(e=T.processTemplate(e,n));}function d(e,t){e&&(e=a(e,n,i,t))&&(e=e.replace(/\\|'/g,"\\$&").replace(/\r\n|\n|\r/g,"\\n"),r.push(e));}n.rmWhitespace&&(e=e.replace(/[\r\n]+/g,"\n").replace(/^\s+|\s+$/gm,"")),s.lastIndex=0,l.lastIndex=0,u.lastIndex=0;for(var g,h=[c.exec,c.interpolate,c.raw].reduce((function(e,n){return e&&n?e+"|"+p(n):n?p(n):e}),""),m=new RegExp("([^]*?)"+p(n.tags[0])+"(-|_)?\\s*("+h+")?\\s*","g"),v=new RegExp("'|\"|`|\\/\\*|(\\s*(-|_)?"+p(n.tags[1])+")","g");g=m.exec(e);){o=g[0].length+g.index;var y=g[1],x=g[2],_=g[3]||"";d(y,x),v.lastIndex=o;for(var w=void 0,b=!1;w=v.exec(e);){if(w[1]){var E=e.slice(o,w.index);m.lastIndex=o=v.lastIndex,i=w[2],b={t:_===c.exec?"e":_===c.raw?"r":_===c.interpolate?"i":"",val:E};break}var I=w[0];if("/*"===I){var R=e.indexOf("*/",v.lastIndex);-1===R&&t("unclosed comment",e,w.index),v.lastIndex=R;}else if("'"===I){l.lastIndex=w.index,l.exec(e)?v.lastIndex=l.lastIndex:t("unclosed string",e,w.index);}else if('"'===I){u.lastIndex=w.index,u.exec(e)?v.lastIndex=u.lastIndex:t("unclosed string",e,w.index);}else if("`"===I){s.lastIndex=w.index,s.exec(e)?v.lastIndex=s.lastIndex:t("unclosed string",e,w.index);}}b?r.push(b):t("unclosed tag",e,g.index+y.length);}if(d(e.slice(o,e.length),!1),n.plugins)for(f=0;f<n.plugins.length;f++){var T;(T=n.plugins[f]).processAST&&(r=T.processAST(r,n));}return r}function d(e,n){var t=f(e,n),r="var tR='',__l,__lP"+(n.include?",include=E.include.bind(E)":"")+(n.includeFile?",includeFile=E.includeFile.bind(E)":"")+"\nfunction layout(p,d){__l=p;__lP=d}\n"+(n.useWith?"with("+n.varName+"||{}){":"")+function(e,n){var t=0,r=e.length,i="";for(;t<r;t++){var a=e[t];if("string"==typeof a){i+="tR+='"+a+"'\n";}else {var o=a.t,c=a.val||"";"r"===o?(n.filter&&(c="E.filter("+c+")"),i+="tR+="+c+"\n"):"i"===o?(n.filter&&(c="E.filter("+c+")"),n.autoEscape&&(c="E.e("+c+")"),i+="tR+="+c+"\n"):"e"===o&&(i+=c+"\n");}}return i}(t,n)+(n.includeFile?"if(__l)tR="+(n.async?"await ":"")+"includeFile(__l,Object.assign("+n.varName+",{body:tR},__lP))\n":n.include?"if(__l)tR="+(n.async?"await ":"")+"include(__l,Object.assign("+n.varName+",{body:tR},__lP))\n":"")+"if(cb){cb(null,tR)} return tR"+(n.useWith?"}":"");if(n.plugins)for(var i=0;i<n.plugins.length;i++){var a=n.plugins[i];a.processFnString&&(r=a.processFnString(r,n));}return r}var g=new(function(){function e(e){this.cache=e;}return e.prototype.define=function(e,n){this.cache[e]=n;},e.prototype.get=function(e){return this.cache[e]},e.prototype.remove=function(e){delete this.cache[e];},e.prototype.reset=function(){thi
});
class TextExpander extends obsidian.Plugin {
constructor(app, plugin) {
super(app, plugin);
this.config = {
3 years ago
autoExpand: false,
defaultTemplate: '- $link',
3 years ago
delay: 300,
3 years ago
excludeCurrent: true,
3 years ago
lineEnding: '<-->',
prefixes: {
header: '^',
footer: '>'
}
3 years ago
};
2 years ago
this.seqs = sequences;
this.leftPanelInfo = {
collapsed: false,
tab: 0,
text: ''
};
this.search = this.search.bind(this);
this.init = this.init.bind(this);
this.autoExpand = this.autoExpand.bind(this);
3 years ago
}
2 years ago
autoExpand() {
return __awaiter(this, void 0, void 0, function* () {
if (!this.config.autoExpand) {
return;
}
const activeLeaf = this.app.workspace.activeLeaf;
if (!activeLeaf) {
return;
}
const activeView = activeLeaf.view;
const isAllowedView = activeView instanceof obsidian.MarkdownView;
if (!isAllowedView) {
return;
}
yield this.init(true);
});
}
onload() {
return __awaiter(this, void 0, void 0, function* () {
this.addSettingTab(new SettingTab(this.app, this));
this.registerMarkdownCodeBlockProcessor('expander', (source, el, ctx) => {
el
.createDiv()
.createEl('button', { text: 'Run expand query' })
.addEventListener('click', this.init.bind(this, false, ctx.getSectionInfo(el).lineStart));
});
this.addCommand({
id: 'editor-expand',
name: 'expand',
callback: this.init,
hotkeys: []
});
this.addCommand({
id: 'editor-expand-all',
name: 'expand all',
callback: () => this.init(true),
hotkeys: []
});
this.app.workspace.on('file-open', this.autoExpand);
const data = yield this.loadData();
if (data) {
this.config = Object.assign(Object.assign({}, this.config), data);
}
});
}
onunload() {
console.log('unloading plugin');
this.app.workspace.off('file-open', this.autoExpand);
}
saveSettings() {
return __awaiter(this, void 0, void 0, function* () {
yield this.saveData(this.config);
});
}
init(proceedAllQueriesOnPage = false, lineToStart) {
return __awaiter(this, void 0, void 0, function* () {
const currentView = this.app.workspace.activeLeaf.view;
// Is on editable view
if (!(currentView instanceof obsidian.MarkdownView)) {
return;
}
const cmDoc = this.cm = currentView.editor;
const curNum = lineToStart || cmDoc.getCursor().line;
const content = cmDoc.getValue();
if (lineToStart) {
cmDoc.setCursor(lineToStart ? lineToStart - 1 : 0);
}
const formatted = splitByLines(content);
const findQueries = getAllExpandersQuery(formatted);
const closestQuery = getClosestQuery(findQueries, curNum);
if (proceedAllQueriesOnPage) {
yield findQueries.reduce((promise, query, i) => promise.then(() => {
const newContent = splitByLines(cmDoc.getValue());
const updatedQueries = getAllExpandersQuery(newContent);
return this.runExpanderCodeBlock(updatedQueries[i], newContent, currentView);
}), Promise.resolve());
}
else {
yield this.runExpanderCodeBlock(closestQuery, formatted, currentView);
}
});
}
runExpanderCodeBlock(query, content, view) {
return __awaiter(this, void 0, void 0, function* () {
const { lineEnding, prefixes } = this.config;
if (!query) {
new Notification('Expand query not found');
return Promise.resolve();
}
this.clearOldResultsInFile(content, query, lineEnding);
const newContent = splitByLines(this.cm.getValue());
if (query.query !== '') {
this.search(query.query);
}
return yield this.runTemplateProcessing(query, getLastLineToReplace(newContent, query, this.config.lineEnding), prefixes, view);
});
}
runTemplateProcessing(query, lastLine, prefixes, currentView) {
var _a;
return __awaiter(this, void 0, void 0, function* () {
let currentFileName = '';
const templateContent = query.template.split('\n');
const { heading, footer, repeatableContent } = this.parseTemplate(prefixes, templateContent);
if (currentView instanceof obsidian.FileView) {
currentFileName = currentView.file.basename;
}
this.saveLeftPanelState();
const searchResults = yield this.getFoundAfterDelay(query.query === '');
const files = extractFilesFromSearchResults(searchResults, currentFileName, this.config.excludeCurrent);
this.restoreLeftPanelState();
currentView.editor.focus();
const currentFileInfo = (currentView instanceof obsidian.FileView)
? yield getFileInfo(this, currentView.file)
: {};
const filesInfo = yield Promise.all(files.map(file => getFileInfo(this, file)));
let changed;
if (query.template.contains("<%")) {
const templateToRender = repeatableContent.join('\n');
const dataToRender = {
current: currentFileInfo,
files: filesInfo
};
changed = yield eta_min.render(templateToRender, dataToRender, { autoEscape: false });
// changed = doT.template(templateToRender, {strip: false})(dataToRender)
}
else {
changed = yield this.generateTemplateFromSequences(files, repeatableContent, searchResults);
}
let result = [
heading,
changed,
footer,
this.config.lineEnding
].filter(e => e).join('\n');
// Do not paste generated content if used changed activeLeaf
const viewBeforeReplace = this.app.workspace.activeLeaf.view;
if (!(viewBeforeReplace instanceof obsidian.MarkdownView) || viewBeforeReplace.file.basename !== currentFileName) {
return;
}
currentView.editor.replaceRange(result, { line: query.end + 1, ch: 0 }, { line: lastLine, ch: ((_a = this.cm.getLine(lastLine)) === null || _a === void 0 ? void 0 : _a.length) || 0 });
return Promise.resolve();
});
}
generateTemplateFromSequences(files, repeatableContent, searchResults) {
return __awaiter(this, void 0, void 0, function* () {
if (!searchResults) {
return '';
}
const changed = yield Promise.all(files
.map((file, i) => __awaiter(this, void 0, void 0, function* () {
const result = yield Promise.all(repeatableContent.map((s) => __awaiter(this, void 0, void 0, function* () { return yield this.applyTemplateToSearchResults(searchResults, file, s, i); })));
return result.join('\n');
})));
return changed.join('\n');
});
}
parseTemplate(prefixes, templateContent) {
const isHeader = (line) => line.startsWith(prefixes.header);
const isFooter = (line) => line.startsWith(prefixes.footer);
const isRepeat = (line) => !isHeader(line) && !isFooter(line);
const heading = templateContent.filter(isHeader).map((s) => s.slice(1)).join('\n');
const footer = templateContent.filter(isFooter).map((s) => s.slice(1)).join('\n');
const repeatableContent = templateContent.filter(isRepeat).filter(e => e).length === 0
? [this.config.defaultTemplate]
: templateContent.filter(isRepeat).filter(e => e);
return { heading, footer, repeatableContent };
}
saveLeftPanelState() {
this.leftPanelInfo = {
3 years ago
collapsed: this.app.workspace.leftSplit.collapsed,
2 years ago
tab: this.getSearchTabIndex(),
text: this.getSearchValue(),
3 years ago
};
2 years ago
}
restoreLeftPanelState() {
const { collapsed, tab, text } = this.leftPanelInfo;
const splitChildren = this.getLeftSplitElement();
this.getSearchView().searchComponent.setValue(text);
if (tab !== splitChildren.currentTab) {
splitChildren.selectTabIndex(tab);
}
if (collapsed) {
3 years ago
this.app.workspace.leftSplit.collapse();
}
2 years ago
}
search(s) {
// @ts-ignore
const globalSearchFn = this.app.internalPlugins.getPluginById('global-search').instance.openGlobalSearch.bind(this);
const search = (query) => globalSearchFn(query);
search(s);
}
getLeftSplitElement() {
3 years ago
// @ts-ignore
2 years ago
return this.app.workspace.leftSplit.children[0];
}
getSearchView() {
const view = this.getLeftSplitElement().children.filter(e => e.getViewState().type === 'search')[0].view;
if ('searchComponent' in view) {
return view;
}
return undefined;
}
getSearchValue() {
const view = this.getSearchView();
if (view) {
return view.searchComponent.getValue();
3 years ago
}
2 years ago
return '';
}
getSearchTabIndex() {
const leftTabs = this.getLeftSplitElement().children;
let searchTabId;
this.app.workspace.iterateAllLeaves((leaf) => {
3 years ago
if (leaf.getViewState().type == "search") {
searchTabId = leaf.id;
}
});
2 years ago
return leftTabs.findIndex((item, _index, _array) => {
3 years ago
if (item.id == searchTabId) {
return true;
}
});
2 years ago
}
;
getFoundAfterDelay(immediate) {
return __awaiter(this, void 0, void 0, function* () {
const searchLeaf = this.app.workspace.getLeavesOfType('search')[0];
const view = yield searchLeaf.open(searchLeaf.view);
if (immediate) {
// @ts-ignore
return Promise.resolve(view.dom.resultDomLookup);
}
return new Promise(resolve => {
setTimeout(() => {
// @ts-ignore
return resolve(view.dom.resultDomLookup);
}, this.config.delay);
3 years ago
});
});
2 years ago
}
applyTemplateToSearchResults(searchResults, file, template, index) {
return __awaiter(this, void 0, void 0, function* () {
const fileContent = (new RegExp(this.seqs.filter(e => e.readContent).map(e => e.name).join('|')).test(template))
? yield this.app.vault.cachedRead(file)
: '';
return this.seqs.reduce((acc, seq) => acc.replace(new RegExp(seq.name, 'gu'), replace => seq.format(this, replace, fileContent, file, searchResults.get(file), index)), template);
3 years ago
});
2 years ago
}
clearOldResultsInFile(content, query, lineEnding) {
3 years ago
var _a;
2 years ago
const lastLine = getLastLineToReplace(content, query, this.config.lineEnding);
this.cm.replaceRange('\n' + lineEnding, { line: query.end + 1, ch: 0 }, { line: lastLine, ch: ((_a = this.cm.getLine(lastLine)) === null || _a === void 0 ? void 0 : _a.length) || 0 });
3 years ago
}
2 years ago
}
class SettingTab extends obsidian.PluginSettingTab {
constructor(app, plugin) {
super(app, plugin);
this.app = app;
this.plugin = plugin;
}
display() {
let { containerEl } = this;
3 years ago
containerEl.empty();
containerEl.createEl('h2', { text: 'Settings for Text Expander' });
new obsidian.Setting(containerEl)
.setName('Auto Expand')
.setDesc('Expand all queries in a file once you open it')
2 years ago
.addToggle(toggle => {
3 years ago
toggle
2 years ago
.setValue(this.plugin.config.autoExpand)
.onChange(value => {
this.plugin.config.autoExpand = value;
this.plugin.saveSettings();
3 years ago
});
});
new obsidian.Setting(containerEl)
.setName('Delay')
.setDesc('Text expander don\' wait until search completed. It waits for a delay and paste result after that.')
2 years ago
.addSlider(slider => {
3 years ago
slider.setLimits(100, 10000, 100);
2 years ago
slider.setValue(this.plugin.config.delay);
slider.onChange(value => {
this.plugin.config.delay = value;
this.plugin.saveSettings();
3 years ago
});
slider.setDynamicTooltip();
});
new obsidian.Setting(containerEl)
.setName('Line ending')
.setDesc('You can specify the text which will appear at the bottom of the generated text.')
2 years ago
.addText(text => {
text.setValue(this.plugin.config.lineEnding)
.onChange(val => {
this.plugin.config.lineEnding = val;
this.plugin.saveSettings();
3 years ago
});
});
new obsidian.Setting(containerEl)
.setName('Default template')
.setDesc('You can specify default template')
2 years ago
.addTextArea(text => {
text.setValue(this.plugin.config.defaultTemplate)
.onChange(val => {
this.plugin.config.defaultTemplate = val;
this.plugin.saveSettings();
3 years ago
});
});
new obsidian.Setting(containerEl)
.setName('Exclude current file')
.setDesc('You can specify should text expander exclude results from current file or not')
2 years ago
.addToggle(toggle => {
3 years ago
toggle
2 years ago
.setValue(this.plugin.config.excludeCurrent)
.onChange(value => {
this.plugin.config.excludeCurrent = value;
this.plugin.saveSettings();
3 years ago
});
});
3 years ago
new obsidian.Setting(containerEl)
.setHeading()
.setName('Prefixes');
new obsidian.Setting(containerEl)
.setName('Header')
.setDesc('Line prefixed by this symbol will be recognized as header')
2 years ago
.addText(text => {
text.setValue(this.plugin.config.prefixes.header)
.onChange(val => {
this.plugin.config.prefixes.header = val;
this.plugin.saveSettings();
3 years ago
});
});
new obsidian.Setting(containerEl)
.setName('Footer')
.setDesc('Line prefixed by this symbol will be recognized as footer')
2 years ago
.addText(text => {
text.setValue(this.plugin.config.prefixes.footer)
.onChange(val => {
this.plugin.config.prefixes.footer = val;
this.plugin.saveSettings();
3 years ago
});
});
3 years ago
new obsidian.Setting(containerEl)
.setName('Sequences')
.setDesc('REGEXP - DESCRIPTION')
2 years ago
.setDesc((() => {
const fragment = new DocumentFragment();
const div = fragment.createEl('div');
this.plugin.seqs
.map(e => e.name + ' - ' + (e.desc || ''))
.map(e => {
const el = fragment.createEl('div');
3 years ago
el.setText(e);
2 years ago
el.setAttribute('style', `
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
margin-bottom: 0.5rem;
padding-bottom: 0.5rem;
`);
3 years ago
return el;
2 years ago
}).forEach(el => {
3 years ago
div.appendChild(el);
});
fragment.appendChild(div);
return fragment;
})());
2 years ago
}
}
3 years ago
module.exports = TextExpander;
2 years ago
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsibm9kZV9tb2R1bGVzL3RzbGliL3RzbGliLmVzNi5qcyIsInNyYy9oZWxwZXJzL2hlbHBlcnMudHMiLCJzcmMvaGVscGVycy9zdHJpbmcudHMiLCJzcmMvaGVscGVycy90ZmlsZS50cyIsInNyYy9zZXF1ZW5jZXMvc2VxdWVuY2VzLnRzIiwic3JjL2hlbHBlcnMvc2VhcmNoLXJlc3VsdHMudHMiLCJub2RlX21vZHVsZXMvZXRhL2Rpc3QvYnJvd3Nlci9ldGEubWluLmpzIiwic3JjL21haW4udHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5Db3B5cmlnaHQgKGMpIE1pY3Jvc29mdCBDb3Jwb3JhdGlvbi5cclxuXHJcblBlcm1pc3Npb24gdG8gdXNlLCBjb3B5LCBtb2RpZnksIGFuZC9vciBkaXN0cmlidXRlIHRoaXMgc29mdHdhcmUgZm9yIGFueVxyXG5wdXJwb3NlIHdpdGggb3Igd2l0aG91dCBmZWUgaXMgaGVyZWJ5IGdyYW50ZWQuXHJcblxyXG5USEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiIEFORCBUSEUgQVVUSE9SIERJU0NMQUlNUyBBTEwgV0FSUkFOVElFUyBXSVRIXHJcblJFR0FSRCBUTyBUSElTIFNPRlRXQVJFIElOQ0xVRElORyBBTEwgSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWVxyXG5BTkQgRklUTkVTUy4gSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUiBCRSBMSUFCTEUgRk9SIEFOWSBTUEVDSUFMLCBESVJFQ1QsXHJcbklORElSRUNULCBPUiBDT05TRVFVRU5USUFMIERBTUFHRVMgT1IgQU5ZIERBTUFHRVMgV0hBVFNPRVZFUiBSRVNVTFRJTkcgRlJPTVxyXG5MT1NTIE9GIFVTRSwgREFUQSBPUiBQUk9GSVRTLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgTkVHTElHRU5DRSBPUlxyXG5PVEhFUiBUT1JUSU9VUyBBQ1RJT04sIEFSSVNJTkcgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgVVNFIE9SXHJcblBFUkZPUk1BTkNFIE9GIFRISVMgU09GVFdBUkUuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqICovXHJcbi8qIGdsb2JhbCBSZWZsZWN0LCBQcm9taXNlICovXHJcblxyXG52YXIgZXh0ZW5kU3RhdGljcyA9IGZ1bmN0aW9uKGQsIGIpIHtcclxuICAgIGV4dGVuZFN0YXRpY3MgPSBPYmplY3Quc2V0UHJvdG90eXBlT2YgfHxcclxuICAgICAgICAoeyBfX3Byb3RvX186IFtdIH0gaW5zdGFuY2VvZiBBcnJheSAmJiBmdW5jdGlvbiAoZCwgYikgeyBkLl9fcHJvdG9fXyA9IGI7IH0pIHx8XHJcbiAgICAgICAgZnVuY3Rpb24gKGQsIGIpIHsgZm9yICh2YXIgcCBpbiBiKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGIsIHApKSBkW3BdID0gYltwXTsgfTtcclxuICAgIHJldHVybiBleHRlbmRTdGF0aWNzKGQsIGIpO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZXh0ZW5kcyhkLCBiKSB7XHJcbiAgICBpZiAodHlwZW9mIGIgIT09IFwiZnVuY3Rpb25cIiAmJiBiICE9PSBudWxsKVxyXG4gICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDbGFzcyBleHRlbmRzIHZhbHVlIFwiICsgU3RyaW5nKGIpICsgXCIgaXMgbm90IGEgY29uc3RydWN0b3Igb3IgbnVsbFwiKTtcclxuICAgIGV4dGVuZFN0YXRpY3MoZCwgYik7XHJcbiAgICBmdW5jdGlvbiBfXygpIHsgdGhpcy5jb25zdHJ1Y3RvciA9IGQ7IH1cclxuICAgIGQucHJvdG90eXBlID0gYiA9PT0gbnVsbCA/IE9iamVjdC5jcmVhdGUoYikgOiAoX18ucHJvdG90eXBlID0gYi5wcm90b3R5cGUsIG5ldyBfXygpKTtcclxufVxyXG5cclxuZXhwb3J0IHZhciBfX2Fzc2lnbiA9IGZ1bmN0aW9uKCkge1xyXG4gICAgX19hc3NpZ24gPSBPYmplY3QuYXNzaWduIHx8IGZ1bmN0aW9uIF9fYXNzaWduKHQpIHtcclxuICAgICAgICBmb3IgKHZhciBzLCBpID0gMSwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgPCBuOyBpKyspIHtcclxuICAgICAgICAgICAgcyA9IGFyZ3VtZW50c1tpXTtcclxuICAgICAgICAgICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApKSB0W3BdID0gc1twXTtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHQ7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gX19hc3NpZ24uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fcmVzdChzLCBlKSB7XHJcbiAgICB2YXIgdCA9IHt9O1xyXG4gICAgZm9yICh2YXIgcCBpbiBzKSBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKHMsIHApICYmIGUuaW5kZXhPZihwKSA8IDApXHJcbiAgICAgICAgdFtwXSA9IHNbcF07XHJcbiAgICBpZiAocyAhPSBudWxsICYmIHR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzID09PSBcImZ1bmN0aW9uXCIpXHJcbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIHAgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKHMpOyBpIDwgcC5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICBpZiAoZS5pbmRleE9mKHBbaV0pIDwgMCAmJiBPYmplY3QucHJvdG90eXBlLnByb3BlcnR5SXNFbnVtZXJhYmxlLmNhbGwocywgcFtpXSkpXHJcbiAgICAgICAgICAgICAgICB0W3BbaV1dID0gc1twW2ldXTtcclxuICAgICAgICB9XHJcbiAgICByZXR1cm4gdDtcclxufVxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIF9fZGVjb3JhdGUoZGVjb3JhdG9ycywgdGFyZ2V0LCBrZXksIGRlc2MpIHtcclxuICAgIHZhciBjID0gYXJndW1lbnRzLmxlbmd0aCwgciA9IGMgPCAzID8gdGFyZ2V0IDogZGVzYyA9PT0gbnVsbCA/IGRlc2MgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHRhcmdldCwga2V5KSA6IGRlc2MsIGQ7XHJcbiAgICBpZiAodHlwZW9mIFJlZmxlY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIFJlZmxlY3QuZGV