'use strict'; var obsidian = require('obsidian'); var state = require('@codemirror/state'); var view = require('@codemirror/view'); var language = require('@codemirror/language'); class SettingsTab extends obsidian.PluginSettingTab { plugin; constructor(app, plugin) { super(app, plugin); this.plugin = plugin; } arrayMove(arr, fromIndex, toIndex) { if (toIndex < 0 || toIndex === arr.length) { return; } const element = arr[fromIndex]; arr[fromIndex] = arr[toIndex]; arr[toIndex] = element; } addRegexSettings() { let desc = document.createDocumentFragment(); desc.append('Custom Regex for specifying patterns to conceal/replace.', desc.createEl('br'), 'Check the ', desc.createEl('a', { href: 'https://github.com/mattcoleanderson/obsidian-dynamic-text-concealer/discussions/19', text: 'List of community made regex', }), ' Discussion for working examples. Feel free to add your own as well.'); new obsidian.Setting(this.containerEl).setHeading().setName('Regular Expressions').setDesc(desc); this.plugin.settings.regexp.forEach((regex, index) => { const setting = new obsidian.Setting(this.containerEl) .addText((text) => { text.setValue(regex).onChange((newRegex) => { if (newRegex && this.plugin.settings.regexp.contains(newRegex)) { // TODO: Log Error return; } this.plugin.settings.regexp[index] = newRegex; this.plugin.saveSettings(); this.plugin.updateEditorExtension(); }); }) .addExtraButton((button) => { button .setIcon('up-chevron-glyph') .setTooltip('Move up') .onClick(() => { console.log('Oh No!'); this.arrayMove(this.plugin.settings.regexp, index, index - 1); this.plugin.saveSettings(); this.display(); this.plugin.updateEditorExtension(); }); }) .addExtraButton((button) => { button .setIcon('down-chevron-glyph') .setTooltip('Move down') .onClick(() => { this.arrayMove(this.plugin.settings.regexp, index, index + 1); this.plugin.saveSettings(); this.display(); this.plugin.updateEditorExtension(); }); }) .addExtraButton((button) => { button .setIcon('cross') .setTooltip('Delete') .onClick(() => { this.plugin.settings.regexp.splice(index, 1); this.plugin.saveSettings(); this.plugin.updateEditorExtension(); this.display(); }); }); setting.infoEl.remove(); setting.controlEl.firstElementChild?.addClass('dtc-setting'); }); new obsidian.Setting(this.containerEl).addButton((button) => { button .setButtonText('Add new regular expression') .setCta() .onClick(() => { this.plugin.settings.regexp.push(''); this.plugin.saveSettings(); this.display(); }); }); } async display() { // This is the outtermost HTML element on the setting tab const { containerEl } = this; containerEl.empty(); // new Setting(containerEl) // .setName('Conceal in Editing Mode') // .setDesc( // `Matched text is concealed in editing mode (live preview), // except when cursor or selection overlaps with matched text.`, // ) // .addToggle((toggle) => // toggle.setValue(this.plugin.settings.doConcealEditMode).onChange(async (value) => { // this.plugin.settings.doConcealEditMode = value; // await this.plugin.saveSettings(); // this.plugin.updateEditorExtension(); // }), // ); // this.setupMatchTable(); this.addRegexSettings(); } } class ConcealMatchDecorator extends view.MatchDecorator { lastSelectionFrom; lastSelectionTo; updateDeco(update, deco) { let updateFrom; let updateTo; if (update.docChanged) { ({ updateFrom, updateTo } = this.updateChanges(update)); } else if (update.selectionSet) { ({ updateFrom, updateTo } = this.updateSelection(update)); } if (updateTo && updateFrom && updateTo - updateFrom <= 1000) { return this['updateRange'](update.view, deco.map(update.changes), updateFrom, updateTo); } else if (update.viewportChanged) { return this.createDeco(update.view); } return deco; } updateChanges(update) { let updateFrom = 1e9; let updateTo = -1; update.changes.iterChanges((_f, _t, from, to) => { if (to > update.view.viewport.from && from < update.view.viewport.to) { updateFrom = update.state.doc.lineAt(Math.min(from, updateFrom)).from; updateTo = update.state.doc.lineAt(Math.max(to, updateTo)).to; } }); return { updateFrom, updateTo }; } /* * updateSelection returns a range to update when a selection has been made * to the document, suchas a moving the cursor of selecting multiple character and line */ updateSelection(update) { const selection = update.state.selection.ranges; // Get the earliest and latest positon of the lines in the selected range let lineFrom = update.state.doc.lineAt(selection[0].from).from; let lineTo = update.state.doc.lineAt(selection[selection.length - 1].to).to; // Return the earliest and latest postions of the current and previous selection range let updateFrom = Math.min(lineFrom, this.lastSelectionFrom); let updateTo = Math.max(lineTo, this.lastSelectionTo); // Retain the current selected range for the next update this.lastSelectionFrom = lineFrom; this.lastSelectionTo = lineTo; return { updateFrom, updateTo }; } } class ConcealViewPlugin { decorations; // list of current decorators in view matchDecorator; // Creates and updates decorators constructor(view$1, regexp) { this.matchDecorator = new ConcealMatchDecorator({ regexp: regexp, decorate: (add, from, to, match, view$1) => { // Define conditions where a decorator should not be added for a match if (this.isCodeblock(view$1, from, to)) return; if (this.selectionAndRangeOverlap(view$1.state.selection, from, to)) return; // Add mark decorator for each capture group in regex for (let i = 1; i < match.length; i++) { if (!match.indices) continue; // Call function to add decorator to DecorationSet for each capture group const startPos = from + (match.indices[i][0] - match.index); const finalPos = from + (match.indices[i][1] - match.index); add(startPos, finalPos, view.Decoration.mark({ class: 'dtc-hide-match' })); } }, }); // Initialize the DecoratorSet if not in source mode this.decorations = this.initializeDecorations(view$1); } /** * isCodeblock returns true if the current current matches * from and to position contains a code block */ isCodeblock(view, from, to) { let isCodeblock = false; language.syntaxTree(view.state).iterate({ from, to, enter: (node) => { if (/^inline-code/.test(node.name) || node.name == 'HyperMD-codeblock_HyperMD-codeblock-bg') { isCodeblock = true; return false; // short circuit child iteration } }, }); return isCodeblock; } /** * selectionAndRangeOverlap returns true if the specified range * overlaps with the current cursor location or selection range */ selectionAndRangeOverlap(selection, rangeFrom, rangeTo) { for (const range of selection.ranges) { if (range.from <= rangeTo && range.to >= rangeFrom) { return true; } } return false; } update(update) { const isSourceMode = !update.state.field(obsidian.editorLivePreviewField); // TODO: Make this a state field const isEditorLayoutChanged = update.transactions.some((t) => t.effects.some((e) => e.is(workspaceLayoutChangeEffect))); // Reinitialize Decorations if sourc mode or recetly switch back to Live Preview if (isSourceMode || isEditorLayoutChanged) { this.decorations = this.initializeDecorations(update.view); return; } // Update DecorationSet with MatchDecorator this.decorations = this.matchDecorator.updateDeco(update, this.decorations); } destroy() { } /** * Initializes DecorationSet. Is disabled if the editor is in source mode. */ initializeDecorations(view$1) { return view$1.state.field(obsidian.editorLivePreviewField) ? this.matchDecorator.createDeco(view$1) : view.Decoration.none; } } const pluginSpec = { decorations: (instance) => instance.decorations, }; /** * concealViewPlugin creates a ViewPlugin to be registers as an editorExtension */ const concealViewPlugin = (regexp) => { return view.ViewPlugin.define((view) => new ConcealViewPlugin(view, regexp), pluginSpec); }; /** * A state effect that represents the workspace's layout change. * Mainly intended to detect when the user switches between live preview and source mode. */ const workspaceLayoutChangeEffect = state.StateEffect.define(); class ConcealPostProcessor { regexp; ELEMENTS_TO_PROCESS = 'p, li'; REGEX_CURLY_REPLACEMENT = '$'; // first capture group; content is not concealed constructor(regexp) { this.regexp = regexp; } conceal = (element) => { // InnterHTML is the only way to preserve element tags during the regex matches. // However, since the replaced text is a capture group, only text in the document itself can cause a replacement let resultString = ''; let prevFinalPos = 0; let match; while ((match = this.regexp.exec(element.innerHTML)) !== null) { for (let i = 1; i < match.length; i++) { if (!match.indices) continue; const replacement = `${match[i]}`; const startPos = match.indices[i][0]; const finalPos = match.indices[i][1]; resultString += element.innerHTML.substring(prevFinalPos, startPos).concat(replacement); prevFinalPos = finalPos; } } if (resultString.length > 0) { element.innerHTML = resultString; } }; // markdownPostProcessor manipulates the DOM of // read mode to conceal clozure syntax process = (htmlElement) => { const elements = htmlElement.querySelectorAll(this.ELEMENTS_TO_PROCESS); // Loop through each element elements.forEach((element) => { this.conceal(element); }); }; } // Settings const DEFAULT_SETTINGS = { doConcealEditMode: true, regexp: ['({{1,2}(?![\\s{])(?:c?\\d+(?::{1,2}|\\|))?)(?:[^}]+)(}{1,2})'], enable: true, }; class DynamicTextConcealPlugin extends obsidian.Plugin { settings; editorExtensions = []; async loadSettings() { this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); } async saveSettings() { await this.saveData(this.settings); } addEditorExtension() { this.editorExtensions.length = 0; if (this.settings.doConcealEditMode) { this.settings.regexp.forEach((regexString) => { if (!regexString) return; // skip if input is empty // Create regex expression from user settings // Note: the 'd' flag, enables regexpmatch indices for enabling clickable replacement text // see: https://github.com/tc39/proposal-regexp-match-indices?tab=readme-ov-file#motivations const regex = new RegExp(regexString, 'gmd'); this.editorExtensions.push(concealViewPlugin(regex)); }); } } updateEditorExtension() { this.addEditorExtension(); this.app.workspace.updateOptions(); } addEvents() { if (this.settings.doConcealEditMode) { // TODO: Add obsidian typing for EditorView to Editor // See : // - https://docs.obsidian.md/Plugins/Editor/Communicating+with+editor+extensions // - https://github.com/blacksmithgu/obsidian-dataview/pull/2088/files this.registerEvent(this.app.workspace.on('layout-change', () => { this.app.workspace.iterateAllLeaves((leaf) => { if (leaf.view instanceof obsidian.MarkdownView && // @ts-expect-error, not typed leaf.view.editor.cm) { // @ts-expect-error, not typed const cm = leaf.view.editor.cm; cm.dispatch({ effects: workspaceLayoutChangeEffect.of(null), }); } }); })); } } addMarkdownPostProcessor() { this.settings.regexp.forEach((regexString) => { const regex = new RegExp(regexString, 'gmd'); // create regex expression from user settings const concealPostProcessor = new ConcealPostProcessor(regex); this.registerMarkdownPostProcessor(concealPostProcessor.process); }); } async onload() { await this.loadSettings(); console.log('Loading Dynamic Text Conceal Plugin'); this.addMarkdownPostProcessor(); this.addEditorExtension(); this.registerEditorExtension(this.editorExtensions); this.addEvents(); this.addSettingTab(new SettingsTab(this.app, this)); } // Releases any resources configured by the plugin onunload() { console.log('Unloading Dynamic Text Conceal Plugin...'); } } module.exports = DynamicTextConcealPlugin; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsInNvdXJjZXMiOlsiLi4vc3JjL3NldHRpbmdzVGFiLnRzIiwiLi4vc3JjL2VkaXRvckV4dGVuc2lvbnMvY29uY2VhbC1tYXRjaC1kZWNvcmF0b3IudHMiLCIuLi9zcmMvZWRpdG9yRXh0ZW5zaW9ucy9jb25jZWFsLXZpZXctcGx1Z2luLnRzIiwiLi4vc3JjL21hcmtkb3duUG9zdFByb2Nlc3NvcnMvY29uY2VhbC1wb3N0LXByb2Nlc3Nvci50cyIsIi4uL3NyYy9tYWluLnRzIl0sInNvdXJjZXNDb250ZW50IjpudWxsLCJuYW1lcyI6WyJQbHVnaW5TZXR0aW5nVGFiIiwiU2V0dGluZyIsIk1hdGNoRGVjb3JhdG9yIiwidmlldyIsIkRlY29yYXRpb24iLCJzeW50YXhUcmVlIiwiZWRpdG9yTGl2ZVByZXZpZXdGaWVsZCIsIlZpZXdQbHVnaW4iLCJTdGF0ZUVmZmVjdCIsIlBsdWdpbiIsIk1hcmtkb3duVmlldyJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQUdNLE1BQU8sV0FBWSxTQUFRQSx5QkFBZ0IsQ0FBQTtBQUNoRCxJQUFBLE1BQU0sQ0FBMkI7SUFFakMsV0FBWSxDQUFBLEdBQVEsRUFBRSxNQUFnQyxFQUFBO0FBQ3JELFFBQUEsS0FBSyxDQUFDLEdBQUcsRUFBRSxNQUFNLENBQUMsQ0FBQztBQUNuQixRQUFBLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO0tBQ3JCO0FBRU8sSUFBQSxTQUFTLENBQUksR0FBUSxFQUFFLFNBQWlCLEVBQUUsT0FBZSxFQUFBO1FBQ2hFLElBQUksT0FBTyxHQUFHLENBQUMsSUFBSSxPQUFPLEtBQUssR0FBRyxDQUFDLE1BQU0sRUFBRTtZQUMxQyxPQUFPO1NBQ1A7QUFDRCxRQUFBLE1BQU0sT0FBTyxHQUFHLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUMvQixHQUFHLENBQUMsU0FBUyxDQUFDLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBQzlCLFFBQUEsR0FBRyxDQUFDLE9BQU8sQ0FBQyxH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