Skip to content

Commit c1df4bb

Browse files
committed
vault backup: 2025-12-27 09:04:57
1 parent b7b37f3 commit c1df4bb

File tree

8 files changed

+668
-10
lines changed

8 files changed

+668
-10
lines changed

.obsidian/community-plugins.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
[
2-
"obsidian-git"
2+
"obsidian-git",
3+
"obsidian-regex-replace"
34
]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"findText": "---(\\r?\\n){2}",
3+
"replaceText": "",
4+
"useRegEx": true,
5+
"selOnly": false,
6+
"caseInsensitive": false,
7+
"processLineBreak": false,
8+
"processTab": false,
9+
"prefillFind": false
10+
}
Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
/*
2+
THIS IS A GENERATED/BUNDLED FILE BY ROLLUP
3+
if you want to view the source visit the plugins github repository
4+
*/
5+
6+
'use strict';
7+
8+
var obsidian = require('obsidian');
9+
10+
/*! *****************************************************************************
11+
Copyright (c) Microsoft Corporation.
12+
13+
Permission to use, copy, modify, and/or distribute this software for any
14+
purpose with or without fee is hereby granted.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
17+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
18+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
19+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
20+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
21+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22+
PERFORMANCE OF THIS SOFTWARE.
23+
***************************************************************************** */
24+
25+
function __awaiter(thisArg, _arguments, P, generator) {
26+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27+
return new (P || (P = Promise))(function (resolve, reject) {
28+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31+
step((generator = generator.apply(thisArg, _arguments || [])).next());
32+
});
33+
}
34+
35+
const DEFAULT_SETTINGS = {
36+
findText: '',
37+
replaceText: '',
38+
useRegEx: true,
39+
selOnly: false,
40+
caseInsensitive: false,
41+
processLineBreak: false,
42+
processTab: false,
43+
prefillFind: false
44+
};
45+
// logThreshold: 0 ... only error messages
46+
// 9 ... verbose output
47+
const logThreshold = 9;
48+
const logger = (logString, logLevel = 0) => { if (logLevel <= logThreshold)
49+
console.log('RegexFiRe: ' + logString); };
50+
class RegexFindReplacePlugin extends obsidian.Plugin {
51+
onload() {
52+
return __awaiter(this, void 0, void 0, function* () {
53+
logger('Loading Plugin...', 9);
54+
yield this.loadSettings();
55+
this.addSettingTab(new RegexFindReplaceSettingTab(this.app, this));
56+
this.addCommand({
57+
id: 'obsidian-regex-replace',
58+
name: 'Find and Replace using regular expressions',
59+
editorCallback: (editor) => {
60+
new FindAndReplaceModal(this.app, editor, this.settings, this).open();
61+
},
62+
});
63+
});
64+
}
65+
onunload() {
66+
logger('Bye!', 9);
67+
}
68+
loadSettings() {
69+
return __awaiter(this, void 0, void 0, function* () {
70+
logger('Loading Settings...', 6);
71+
this.settings = Object.assign({}, DEFAULT_SETTINGS, yield this.loadData());
72+
logger(' findVal: ' + this.settings.findText, 6);
73+
logger(' replaceText: ' + this.settings.replaceText, 6);
74+
logger(' caseInsensitive: ' + this.settings.caseInsensitive, 6);
75+
logger(' processLineBreak: ' + this.settings.processLineBreak, 6);
76+
});
77+
}
78+
saveSettings() {
79+
return __awaiter(this, void 0, void 0, function* () {
80+
yield this.saveData(this.settings);
81+
});
82+
}
83+
}
84+
class FindAndReplaceModal extends obsidian.Modal {
85+
constructor(app, editor, settings, plugin) {
86+
super(app);
87+
this.editor = editor;
88+
this.settings = settings;
89+
this.plugin = plugin;
90+
}
91+
onOpen() {
92+
const { contentEl, titleEl, editor, modalEl } = this;
93+
modalEl.addClass('find-replace-modal');
94+
titleEl.setText('Regex Find/Replace');
95+
const rowClass = 'row';
96+
const divClass = 'div';
97+
const noSelection = editor.getSelection() === '';
98+
let regexFlags = 'gm';
99+
if (this.settings.caseInsensitive)
100+
regexFlags = regexFlags.concat('i');
101+
logger('No text selected?: ' + noSelection, 9);
102+
const addTextComponent = (label, placeholder, postfix = '') => {
103+
const containerEl = document.createElement(divClass);
104+
containerEl.addClass(rowClass);
105+
const targetEl = document.createElement(divClass);
106+
targetEl.addClass('input-wrapper');
107+
const labelEl = document.createElement(divClass);
108+
labelEl.addClass('input-label');
109+
labelEl.setText(label);
110+
const labelEl2 = document.createElement(divClass);
111+
labelEl2.addClass('postfix-label');
112+
labelEl2.setText(postfix);
113+
containerEl.appendChild(labelEl);
114+
containerEl.appendChild(targetEl);
115+
containerEl.appendChild(labelEl2);
116+
const component = new obsidian.TextComponent(targetEl);
117+
component.setPlaceholder(placeholder);
118+
contentEl.append(containerEl);
119+
return [component, labelEl2];
120+
};
121+
const addToggleComponent = (label, tooltip, hide = false) => {
122+
const containerEl = document.createElement(divClass);
123+
containerEl.addClass(rowClass);
124+
const targetEl = document.createElement(divClass);
125+
targetEl.addClass(rowClass);
126+
const component = new obsidian.ToggleComponent(targetEl);
127+
component.setTooltip(tooltip);
128+
const labelEl = document.createElement(divClass);
129+
labelEl.addClass('check-label');
130+
labelEl.setText(label);
131+
containerEl.appendChild(labelEl);
132+
containerEl.appendChild(targetEl);
133+
if (!hide)
134+
contentEl.appendChild(containerEl);
135+
return component;
136+
};
137+
// Create input fields
138+
const findRow = addTextComponent('Find:', 'e.g. (.*)', '/' + regexFlags);
139+
const findInputComponent = findRow[0];
140+
const findRegexFlags = findRow[1];
141+
const replaceRow = addTextComponent('Replace:', 'e.g. $1', this.settings.processLineBreak ? '\\n=LF' : '');
142+
const replaceWithInputComponent = replaceRow[0];
143+
// Create and show regular expression toggle switch
144+
const regToggleComponent = addToggleComponent('Use regular expressions', 'If enabled, regular expressions in the find field are processed as such, and regex groups might be addressed in the replace field');
145+
// Update regex-flags label if regular expressions are enabled or disabled
146+
regToggleComponent.onChange(regNew => {
147+
if (regNew) {
148+
findRegexFlags.setText('/' + regexFlags);
149+
}
150+
else {
151+
findRegexFlags.setText('');
152+
}
153+
});
154+
// Create and show selection toggle switch only if any text is selected
155+
const selToggleComponent = addToggleComponent('Replace only in selection', 'If enabled, replaces only occurances in the currently selected text', noSelection);
156+
// Create Buttons
157+
const buttonContainerEl = document.createElement(divClass);
158+
buttonContainerEl.addClass(rowClass);
159+
const submitButtonTarget = document.createElement(divClass);
160+
submitButtonTarget.addClass('button-wrapper');
161+
submitButtonTarget.addClass(rowClass);
162+
const cancelButtonTarget = document.createElement(divClass);
163+
cancelButtonTarget.addClass('button-wrapper');
164+
cancelButtonTarget.addClass(rowClass);
165+
const submitButtonComponent = new obsidian.ButtonComponent(submitButtonTarget);
166+
const cancelButtonComponent = new obsidian.ButtonComponent(cancelButtonTarget);
167+
cancelButtonComponent.setButtonText('Cancel');
168+
cancelButtonComponent.onClick(() => {
169+
logger('Action cancelled.', 8);
170+
this.close();
171+
});
172+
submitButtonComponent.setButtonText('Replace All');
173+
submitButtonComponent.setCta();
174+
submitButtonComponent.onClick(() => {
175+
let resultString = 'No match';
176+
let scope = '';
177+
const searchString = findInputComponent.getValue();
178+
let replaceString = replaceWithInputComponent.getValue();
179+
const selectedText = editor.getSelection();
180+
if (searchString === '') {
181+
new obsidian.Notice('Nothing to search for!');
182+
return;
183+
}
184+
// Replace line breaks in find-field if option is enabled
185+
if (this.settings.processLineBreak) {
186+
logger('Replacing linebreaks in replace-field', 9);
187+
logger(' old: ' + replaceString, 9);
188+
replaceString = replaceString.replace(/\\n/gm, '\n');
189+
logger(' new: ' + replaceString, 9);
190+
}
191+
// Replace line breaks in find-field if option is enabled
192+
if (this.settings.processTab) {
193+
logger('Replacing tabs in replace-field', 9);
194+
logger(' old: ' + replaceString, 9);
195+
replaceString = replaceString.replace(/\\t/gm, '\t');
196+
logger(' new: ' + replaceString, 9);
197+
}
198+
// Check if regular expressions should be used
199+
if (regToggleComponent.getValue()) {
200+
logger('USING regex with flags: ' + regexFlags, 8);
201+
const searchRegex = new RegExp(searchString, regexFlags);
202+
if (!selToggleComponent.getValue()) {
203+
logger(' SCOPE: Full document', 9);
204+
const documentText = editor.getValue();
205+
const rresult = documentText.match(searchRegex);
206+
if (rresult) {
207+
editor.setValue(documentText.replace(searchRegex, replaceString));
208+
resultString = `Made ${rresult.length} replacement(s) in document`;
209+
}
210+
}
211+
else {
212+
logger(' SCOPE: Selection', 9);
213+
const rresult = selectedText.match(searchRegex);
214+
if (rresult) {
215+
editor.replaceSelection(selectedText.replace(searchRegex, replaceString));
216+
resultString = `Made ${rresult.length} replacement(s) in selection`;
217+
}
218+
}
219+
}
220+
else {
221+
logger('NOT using regex', 8);
222+
let nrOfHits = 0;
223+
if (!selToggleComponent.getValue()) {
224+
logger(' SCOPE: Full document', 9);
225+
scope = 'selection';
226+
const documentText = editor.getValue();
227+
const documentSplit = documentText.split(searchString);
228+
nrOfHits = documentSplit.length - 1;
229+
editor.setValue(documentSplit.join(replaceString));
230+
}
231+
else {
232+
logger(' SCOPE: Selection', 9);
233+
scope = 'document';
234+
const selectedSplit = selectedText.split(searchString);
235+
nrOfHits = selectedSplit.length - 1;
236+
editor.replaceSelection(selectedSplit.join(replaceString));
237+
}
238+
resultString = `Made ${nrOfHits} replacement(s) in ${scope}`;
239+
}
240+
// Saving settings (find/replace text and toggle switch states)
241+
this.settings.findText = searchString;
242+
this.settings.replaceText = replaceString;
243+
this.settings.useRegEx = regToggleComponent.getValue();
244+
this.settings.selOnly = selToggleComponent.getValue();
245+
this.plugin.saveData(this.settings);
246+
this.close();
247+
new obsidian.Notice(resultString);
248+
});
249+
// Apply settings
250+
regToggleComponent.setValue(this.settings.useRegEx);
251+
selToggleComponent.setValue(this.settings.selOnly);
252+
replaceWithInputComponent.setValue(this.settings.replaceText);
253+
// Check if the prefill find option is enabled and the selection does not contain linebreaks
254+
if (this.settings.prefillFind && editor.getSelection().indexOf('\n') < 0 && !noSelection) {
255+
logger('Found selection without linebreaks and option is enabled -> fill', 9);
256+
findInputComponent.setValue(editor.getSelection());
257+
selToggleComponent.setValue(false);
258+
}
259+
else {
260+
logger('Restore find text', 9);
261+
findInputComponent.setValue(this.settings.findText);
262+
}
263+
// Add button row to dialog
264+
buttonContainerEl.appendChild(submitButtonTarget);
265+
buttonContainerEl.appendChild(cancelButtonTarget);
266+
contentEl.appendChild(buttonContainerEl);
267+
// If no text is selected, disable selection-toggle-switch
268+
if (noSelection)
269+
selToggleComponent.setValue(false);
270+
}
271+
onClose() {
272+
const { contentEl } = this;
273+
contentEl.empty();
274+
}
275+
}
276+
class RegexFindReplaceSettingTab extends obsidian.PluginSettingTab {
277+
constructor(app, plugin) {
278+
super(app, plugin);
279+
this.plugin = plugin;
280+
}
281+
display() {
282+
const { containerEl } = this;
283+
containerEl.empty();
284+
containerEl.createEl('h4', { text: 'Regular Expression Settings' });
285+
new obsidian.Setting(containerEl)
286+
.setName('Case Insensitive')
287+
.setDesc('When using regular expressions, apply the \'/i\' modifier for case insensitive search)')
288+
.addToggle(toggle => toggle
289+
.setValue(this.plugin.settings.caseInsensitive)
290+
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
291+
logger('Settings update: caseInsensitive: ' + value);
292+
this.plugin.settings.caseInsensitive = value;
293+
yield this.plugin.saveSettings();
294+
})));
295+
containerEl.createEl('h4', { text: 'General Settings' });
296+
new obsidian.Setting(containerEl)
297+
.setName('Process \\n as line break')
298+
.setDesc('When \'\\n\' is used in the replace field, a \'line break\' will be inserted accordingly')
299+
.addToggle(toggle => toggle
300+
.setValue(this.plugin.settings.processLineBreak)
301+
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
302+
logger('Settings update: processLineBreak: ' + value);
303+
this.plugin.settings.processLineBreak = value;
304+
yield this.plugin.saveSettings();
305+
})));
306+
new obsidian.Setting(containerEl)
307+
.setName('Prefill Find Field')
308+
.setDesc('Copy the currently selected text (if any) into the \'Find\' text field. This setting is only applied if the selection does not contain linebreaks')
309+
.addToggle(toggle => toggle
310+
.setValue(this.plugin.settings.prefillFind)
311+
.onChange((value) => __awaiter(this, void 0, void 0, function* () {
312+
logger('Settings update: prefillFind: ' + value);
313+
this.plugin.settings.prefillFind = value;
314+
yield this.plugin.saveSettings();
315+
})));
316+
}
317+
}
318+
319+
module.exports = RegexFindReplacePlugin;
320+
321+
322+
/* nosourcemap */
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"author": "Martin Eder",
3+
"authorUrl": "https://www.gruware.org",
4+
"description": "Find and replace text using regular expressions.",
5+
"id": "obsidian-regex-replace",
6+
"isDesktopOnly": false,
7+
"minAppVersion": "0.12.17",
8+
"name": "Regex Find/Replace",
9+
"version": "1.2.0"
10+
}

0 commit comments

Comments
 (0)