From 470dd8176d42c7a03987bab5964d3776c4212627 Mon Sep 17 00:00:00 2001 From: Oleh Lustenko Date: Fri, 16 Sep 2022 09:28:09 +0300 Subject: [PATCH 1/5] initial layout --- main.ts | 67 +++++++++++++++++++++++++++++++- src/services/obsidian.service.ts | 16 ++++++++ styles.css | 33 ++++++++++++++++ 3 files changed, 115 insertions(+), 1 deletion(-) diff --git a/main.ts b/main.ts index 60ab512..26c0c38 100644 --- a/main.ts +++ b/main.ts @@ -13,6 +13,7 @@ import { renameFilesInObsidian } from './src/services/file.service'; import { createPreviewElement } from './src/components/PreviewElement'; import { getObsidianFilesByFolderName, + getObsidianFilesByRegExp, getObsidianFilesWithTagName, } from './src/services/obsidian.service'; import { renderPreviewFiles } from './src/components/RenderPreviewFiles'; @@ -23,7 +24,8 @@ interface BulkRenamePluginSettings { existingSymbol: string; replacePattern: string; tags: string[]; - viewType: 'tags' | 'folder'; + userRegExp: string; + viewType: 'tags' | 'folder' | 'regexp'; } const DEFAULT_SETTINGS: BulkRenamePluginSettings = { @@ -31,6 +33,7 @@ const DEFAULT_SETTINGS: BulkRenamePluginSettings = { fileNames: [], existingSymbol: '', replacePattern: '', + userRegExp: '', tags: [], viewType: 'folder', }; @@ -38,10 +41,15 @@ const DEFAULT_SETTINGS: BulkRenamePluginSettings = { const isViewTypeFolder = ({ settings }: BulkRenamePlugin) => { return settings.viewType === 'folder'; }; + const isViewTypeTags = ({ settings }: BulkRenamePlugin) => { return settings.viewType === 'tags'; }; +const isViewTypeRegExp = ({ settings }: BulkRenamePlugin) => { + return settings.viewType === 'regexp'; +}; + class BulkRenamePlugin extends Plugin { settings: BulkRenamePluginSettings; @@ -97,6 +105,7 @@ export class BulkRenameSettingsTab extends PluginSettingTab { this.renderTabs(); this.renderFileLocation(); this.renderTagNames(); + this.renderRegExpInput(); this.renderReplaceSymbol(); this.renderFilesAndPreview(); this.renderRenameFiles(); @@ -127,6 +136,17 @@ export class BulkRenameSettingsTab extends PluginSettingTab { await this.plugin.saveSettings(); this.display(); }); + }) + .addButton((button) => { + button.setButtonText('Search by RegExp'); + if (isViewTypeRegExp(this.plugin)) { + button.setCta(); + } + button.onClick(async () => { + this.plugin.settings.viewType = 'regexp'; + await this.plugin.saveSettings(); + this.display(); + }); }); } @@ -185,6 +205,38 @@ export class BulkRenameSettingsTab extends PluginSettingTab { }); } + renderRegExpInput() { + if (!isViewTypeRegExp(this.plugin)) { + return; + } + new Setting(this.containerEl) + .setName('RegExp') + .setDesc('all files by titles will be found') + .addSearch((cb) => { + // @ts-ignore + cb.inputEl.addEventListener('keydown', (event) => { + if (event.key !== 'Enter') { + return; + } + const target = event.target as HTMLInputElement; + + this.plugin.settings.userRegExp = target.value; + this.plugin.saveSettings(); + }); + cb.setPlaceholder('Example: #tag, #tag2') + .setValue(this.plugin.settings.userRegExp) + .onChange((newFolder) => { + this.plugin.settings.userRegExp = newFolder; + this.plugin.saveSettings(); + this.getFilesByRegExp(); + }); + // @ts-ignore + cb.containerEl.addClass('bulk_regexp'); + cb.inputEl.addClass('bulk_input'); + cb.inputEl.onblur = this.reRenderPreview; + }); + } + renderReplaceSymbol() { const { settings } = this.plugin; @@ -296,6 +348,12 @@ export class BulkRenameSettingsTab extends PluginSettingTab { this.getFilesByTags(); return; } + + if (isViewTypeRegExp(this.plugin)) { + this.getFilesByRegExp(); + return; + } + this.getFilesByFolder(); } @@ -312,6 +370,13 @@ export class BulkRenameSettingsTab extends PluginSettingTab { this.plugin, ); } + + getFilesByRegExp() { + this.plugin.settings.fileNames = getObsidianFilesByRegExp( + this.app, + this.plugin, + ); + } } export default BulkRenamePlugin; diff --git a/src/services/obsidian.service.ts b/src/services/obsidian.service.ts index c383da2..d715fa3 100644 --- a/src/services/obsidian.service.ts +++ b/src/services/obsidian.service.ts @@ -17,6 +17,22 @@ export const getObsidianFilesByFolderName = ( return filesSortedByName; }; +export const getObsidianFilesByRegExp = ( + app: App, + plugin: BulkRenamePlugin, +) => { + const { userRegExp } = plugin.settings; + const abstractFiles = app.vault.getAllLoadedFiles(); + + const files = abstractFiles.filter( + (file) => file instanceof TFile && file.parent.name.includes(userRegExp), + ) as TFile[]; + + const filesSortedByName = sortFilesByName(files); + + return filesSortedByName; +}; + export const getObsidianFilesWithTagName = ( app: App, plugin: BulkRenamePlugin, diff --git a/styles.css b/styles.css index e62dd93..0fa17f3 100644 --- a/styles.css +++ b/styles.css @@ -23,3 +23,36 @@ .bulk_preview_label { margin-right: 15px; } + +.bulk_regexp { + width: 100%; +} + +.bulk_regexp > input { + color: green; + padding: 0 28px 0 14px; + font-size: 20px; + font-weight: 700; +} + +.bulk_regexp:before { + content: '/'; + top: 2px; + left: -15px; +} + +.bulk_regexp:after { + content: '/'; + bottom: 5px; + right: -15px; +} + +.bulk_regexp:before, +.bulk_regexp:after { + color: #000080; + font-size: 30px; + /*background-color: #cccccc;*/ + display: block; + /*text-align: center;*/ + position: absolute; +} From 7ddd6525c6ab11e784e08250838ff03e7c944378 Mon Sep 17 00:00:00 2001 From: Oleh Lustenko Date: Sun, 18 Sep 2022 08:33:58 +0300 Subject: [PATCH 2/5] add suggestions for regExp flags, mark selected flags, make regExp field looks pretty --- main.ts | 54 ++++++++++++++++++++++----- src/components/RegExpBackslash.ts | 6 +++ src/constants/RegExpFlags.ts | 26 +++++++++++++ src/suggestions/RegExpFlagsSuggest.ts | 42 +++++++++++++++++++++ src/suggestions/suggest.ts | 13 +++++-- styles.css | 41 +++++++++----------- 6 files changed, 146 insertions(+), 36 deletions(-) create mode 100644 src/components/RegExpBackslash.ts create mode 100644 src/constants/RegExpFlags.ts create mode 100644 src/suggestions/RegExpFlagsSuggest.ts diff --git a/main.ts b/main.ts index 26c0c38..3739eb7 100644 --- a/main.ts +++ b/main.ts @@ -17,6 +17,13 @@ import { getObsidianFilesWithTagName, } from './src/services/obsidian.service'; import { renderPreviewFiles } from './src/components/RenderPreviewFiles'; +import { createBackslash } from './src/components/RegExpBackslash'; +import { + REGEXP_FLAGS, + RegExpFlag, + RegExpFlags, +} from './src/constants/RegExpFlags'; +import { RegExpFlagsSuggest } from './src/suggestions/RegExpFlagsSuggest'; interface BulkRenamePluginSettings { folderName: string; @@ -25,6 +32,10 @@ interface BulkRenamePluginSettings { replacePattern: string; tags: string[]; userRegExp: string; + regExpState: { + regExp: string; + flags: RegExpFlag[]; + }; viewType: 'tags' | 'folder' | 'regexp'; } @@ -34,6 +45,10 @@ const DEFAULT_SETTINGS: BulkRenamePluginSettings = { existingSymbol: '', replacePattern: '', userRegExp: '', + regExpState: { + regExp: '', + flags: [], + }, tags: [], viewType: 'folder', }; @@ -158,7 +173,7 @@ export class BulkRenameSettingsTab extends PluginSettingTab { .setName('Folder location') .setDesc('Find files within the folder') .addSearch((cb) => { - new FolderSuggest(this.app, cb.inputEl); + new FolderSuggest(this.app, cb.inputEl, this.plugin); cb.setPlaceholder('Example: folder1/') .setValue(this.plugin.settings.folderName) .onChange((newFolder) => { @@ -212,7 +227,9 @@ export class BulkRenameSettingsTab extends PluginSettingTab { new Setting(this.containerEl) .setName('RegExp') .setDesc('all files by titles will be found') - .addSearch((cb) => { + .addText((cb) => { + const backslash = createBackslash('/'); + cb.inputEl.insertAdjacentElement('beforebegin', backslash); // @ts-ignore cb.inputEl.addEventListener('keydown', (event) => { if (event.key !== 'Enter') { @@ -220,21 +237,40 @@ export class BulkRenameSettingsTab extends PluginSettingTab { } const target = event.target as HTMLInputElement; - this.plugin.settings.userRegExp = target.value; + this.plugin.settings.regExpState.regExp = target.value; this.plugin.saveSettings(); }); - cb.setPlaceholder('Example: #tag, #tag2') - .setValue(this.plugin.settings.userRegExp) + cb.setPlaceholder('Put your RegExp here') + .setValue(this.plugin.settings.regExpState.regExp) .onChange((newFolder) => { - this.plugin.settings.userRegExp = newFolder; + this.plugin.settings.regExpState.regExp = newFolder; this.plugin.saveSettings(); this.getFilesByRegExp(); }); // @ts-ignore - cb.containerEl.addClass('bulk_regexp'); - cb.inputEl.addClass('bulk_input'); + cb.inputEl.addClass('bulk_regexp'); cb.inputEl.onblur = this.reRenderPreview; - }); + }) + .addText((cb) => { + new RegExpFlagsSuggest(this.app, cb.inputEl, this.plugin); + const backslash = createBackslash('/'); + cb.inputEl.insertAdjacentElement('beforebegin', backslash); + cb.inputEl.addEventListener('keydown', (event) => { + // @ts-ignore + event.stopPropagation(); + event.stopImmediatePropagation(); + event.preventDefault(); + }); + cb.setPlaceholder('flags here') + // .setDisabled(true) + .setValue(this.plugin.settings.regExpState.flags.join('')) + .onChange((flag: RegExpFlag) => { + this.plugin.saveSettings(); + this.getFilesByRegExp(); + }); + cb.inputEl.addClass('bulk_regexp_flags'); + }) + .controlEl.addClass('bulk_regexp_control'); } renderReplaceSymbol() { diff --git a/src/components/RegExpBackslash.ts b/src/components/RegExpBackslash.ts new file mode 100644 index 0000000..1b5c42f --- /dev/null +++ b/src/components/RegExpBackslash.ts @@ -0,0 +1,6 @@ +export const createBackslash = (textContent = '=> => => =>') => { + const previewLabel = window.document.createElement('div'); + previewLabel.className = 'bulk_regexp_slash'; + previewLabel.textContent = textContent; + return previewLabel; +}; diff --git a/src/constants/RegExpFlags.ts b/src/constants/RegExpFlags.ts new file mode 100644 index 0000000..e44d0ff --- /dev/null +++ b/src/constants/RegExpFlags.ts @@ -0,0 +1,26 @@ +export type RegExpFlag = + | 'g' + | 'm' + | 'i' + | 'x' + | 's' + | 'u' + | 'U' + | 'A' + | 'J' + | 'D'; + +export const REGEXP_FLAGS = [ + 'g', + 'm', + 'i', + 'x', + 's', + 'u', + 'U', + 'A', + 'J', + 'D', +] as const; + +export type RegExpFlags = typeof REGEXP_FLAGS; diff --git a/src/suggestions/RegExpFlagsSuggest.ts b/src/suggestions/RegExpFlagsSuggest.ts new file mode 100644 index 0000000..eace9a5 --- /dev/null +++ b/src/suggestions/RegExpFlagsSuggest.ts @@ -0,0 +1,42 @@ +// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes + +import { TextInputSuggest } from './suggest'; +import { REGEXP_FLAGS, RegExpFlag } from '../constants/RegExpFlags'; + +export class RegExpFlagsSuggest extends TextInputSuggest { + // @ts-ignore TODO refactor types types + getSuggestions() { + return REGEXP_FLAGS; + } + + renderSuggestion = (flag: RegExpFlag, el: HTMLElement) => { + const { regExpState } = this.plugin.settings; + const hasFlag = regExpState.flags.includes(flag); + if (hasFlag) { + el.addClass('bulk-flag-selected'); + } else { + el.removeClass('bulk-flag-selected'); + } + el.setText(flag); + }; + + selectSuggestion = (flag: RegExpFlag, event: MouseEvent | KeyboardEvent) => { + const { regExpState } = this.plugin.settings; + const target = event.target as HTMLDivElement; + + const hasFlag = regExpState.flags.includes(flag); + if (hasFlag) { + regExpState.flags = regExpState.flags.filter((existingFlag) => { + return existingFlag !== flag; + }); + } else { + regExpState.flags = [...regExpState.flags, flag]; + } + target.classList.toggle('bulk-flag-selected'); + this.inputEl.value = regExpState.flags.join(''); + // this.inputEl.trigger('input'); + // this.settings.plugin.settings.regExpState.flags.push(file); + // this.inputEl.trigger('input'); + // this.close(); + }; +} diff --git a/src/suggestions/suggest.ts b/src/suggestions/suggest.ts index 53f69ad..3954250 100644 --- a/src/suggestions/suggest.ts +++ b/src/suggestions/suggest.ts @@ -2,6 +2,7 @@ import { App, ISuggestOwner, Scope } from 'obsidian'; import { createPopper, Instance as PopperInstance } from '@popperjs/core'; +import BulkRenamePlugin from '../../main'; const wrapAround = (value: number, size: number): number => { return ((value % size) + size) % size; @@ -104,6 +105,7 @@ class Suggest { export abstract class TextInputSuggest implements ISuggestOwner { protected app: App; + protected plugin: BulkRenamePlugin; protected inputEl: HTMLInputElement | HTMLTextAreaElement; private popper: PopperInstance; @@ -111,7 +113,12 @@ export abstract class TextInputSuggest implements ISuggestOwner { private suggestEl: HTMLElement; private suggest: Suggest; - constructor(app: App, inputEl: HTMLInputElement | HTMLTextAreaElement) { + constructor( + app: App, + inputEl: HTMLInputElement | HTMLTextAreaElement, + plugin: BulkRenamePlugin, + ) { + this.plugin = plugin; this.app = app; this.inputEl = inputEl; this.scope = new Scope(); @@ -191,7 +198,7 @@ export abstract class TextInputSuggest implements ISuggestOwner { this.suggestEl.detach(); } - abstract getSuggestions(inputStr: string): T[]; + abstract getSuggestions(inputStr?: string): T[]; abstract renderSuggestion(item: T, el: HTMLElement): void; - abstract selectSuggestion(item: T): void; + abstract selectSuggestion(item: T, evt: MouseEvent | KeyboardEvent): void; } diff --git a/styles.css b/styles.css index 0fa17f3..3210dbf 100644 --- a/styles.css +++ b/styles.css @@ -24,35 +24,28 @@ margin-right: 15px; } -.bulk_regexp { +.bulk_regexp_control { + border: 1px solid var(--background-modifier-border); +} + +.bulk_regexp_control > input { + border: none; +} + +.bulk_regexp, +.bulk_regexp_flags { width: 100%; } -.bulk_regexp > input { - color: green; - padding: 0 28px 0 14px; - font-size: 20px; - font-weight: 700; +.bulk_regexp_flags { + caret-color: transparent; } -.bulk_regexp:before { - content: '/'; - top: 2px; - left: -15px; +.bulk_regexp_slash { + font-size: 1.5em; + opacity: 0.5; } -.bulk_regexp:after { - content: '/'; - bottom: 5px; - right: -15px; -} - -.bulk_regexp:before, -.bulk_regexp:after { - color: #000080; - font-size: 30px; - /*background-color: #cccccc;*/ - display: block; - /*text-align: center;*/ - position: absolute; +.bulk-flag-selected { + background-color: lavender !important; } From 7b7c672d6e57508750df5f7d0e4ccd1434b0b656 Mon Sep 17 00:00:00 2001 From: Oleh Lustenko Date: Sun, 18 Sep 2022 09:11:05 +0300 Subject: [PATCH 3/5] find files by RegExp --- main.ts | 10 +---- package-lock.json | 65 ++++++++++++++++++++++++++- package.json | 3 +- src/components/RegExpBackslash.ts | 2 +- src/constants/RegExpFlags.ts | 23 +++------- src/services/file.service.ts | 6 +-- src/services/obsidian.service.ts | 16 ++++--- src/suggestions/RegExpFlagsSuggest.ts | 5 +-- 8 files changed, 89 insertions(+), 41 deletions(-) diff --git a/main.ts b/main.ts index 3739eb7..10e1bf7 100644 --- a/main.ts +++ b/main.ts @@ -18,11 +18,7 @@ import { } from './src/services/obsidian.service'; import { renderPreviewFiles } from './src/components/RenderPreviewFiles'; import { createBackslash } from './src/components/RegExpBackslash'; -import { - REGEXP_FLAGS, - RegExpFlag, - RegExpFlags, -} from './src/constants/RegExpFlags'; +import { RegExpFlag } from './src/constants/RegExpFlags'; import { RegExpFlagsSuggest } from './src/suggestions/RegExpFlagsSuggest'; interface BulkRenamePluginSettings { @@ -31,7 +27,6 @@ interface BulkRenamePluginSettings { existingSymbol: string; replacePattern: string; tags: string[]; - userRegExp: string; regExpState: { regExp: string; flags: RegExpFlag[]; @@ -44,7 +39,6 @@ const DEFAULT_SETTINGS: BulkRenamePluginSettings = { fileNames: [], existingSymbol: '', replacePattern: '', - userRegExp: '', regExpState: { regExp: '', flags: [], @@ -196,7 +190,6 @@ export class BulkRenameSettingsTab extends PluginSettingTab { .setName('Tag names ') .setDesc('all files with the tags will be found') .addSearch((cb) => { - // @ts-ignore cb.inputEl.addEventListener('keydown', (event) => { if (event.key !== 'Enter') { return; @@ -267,6 +260,7 @@ export class BulkRenameSettingsTab extends PluginSettingTab { .onChange((flag: RegExpFlag) => { this.plugin.saveSettings(); this.getFilesByRegExp(); + this.reRenderPreview(); }); cb.inputEl.addClass('bulk_regexp_flags'); }) diff --git a/package-lock.json b/package-lock.json index c441e2d..184f803 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,8 @@ "version": "0.3.5", "license": "MIT", "dependencies": { - "@popperjs/core": "^2.11.2" + "@popperjs/core": "^2.11.2", + "xregexp": "^5.1.1" }, "devDependencies": { "@types/jest": "^28.1.8", @@ -855,6 +856,18 @@ "source-map": "^0.6.0" } }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz", + "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==", + "dependencies": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.18.10", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", @@ -3367,6 +3380,16 @@ "node": ">=0.10.0" } }, + "node_modules/core-js-pure": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.1.tgz", + "integrity": "sha512-7Fr74bliUDdeJCBMxkkIuQ4xfxn/SwrVg+HkJUAoNEXVqYLv55l6Af0dJ5Lq2YBUW9yKqSkLXaS5SYPK6MGa/A==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -8421,6 +8444,11 @@ "node": ">= 4" } }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, "node_modules/regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -10009,6 +10037,14 @@ "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, + "node_modules/xregexp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-5.1.1.tgz", + "integrity": "sha512-fKXeVorD+CzWvFs7VBuKTYIW63YD1e1osxwQ8caZ6o1jg6pDAbABDG54LCIq0j5cy7PjRvGIq6sef9DYPXpncg==", + "dependencies": { + "@babel/runtime-corejs3": "^7.16.5" + } + }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -10669,6 +10705,15 @@ } } }, + "@babel/runtime-corejs3": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz", + "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==", + "requires": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.4" + } + }, "@babel/template": { "version": "7.18.10", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz", @@ -12606,6 +12651,11 @@ "integrity": "sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==", "dev": true }, + "core-js-pure": { + "version": "3.25.1", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.1.tgz", + "integrity": "sha512-7Fr74bliUDdeJCBMxkkIuQ4xfxn/SwrVg+HkJUAoNEXVqYLv55l6Af0dJ5Lq2YBUW9yKqSkLXaS5SYPK6MGa/A==" + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -16376,6 +16426,11 @@ "source-map": "~0.6.1" } }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -17596,6 +17651,14 @@ "signal-exit": "^3.0.7" } }, + "xregexp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-5.1.1.tgz", + "integrity": "sha512-fKXeVorD+CzWvFs7VBuKTYIW63YD1e1osxwQ8caZ6o1jg6pDAbABDG54LCIq0j5cy7PjRvGIq6sef9DYPXpncg==", + "requires": { + "@babel/runtime-corejs3": "^7.16.5" + } + }, "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/package.json b/package.json index 23d0671..77550c2 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "author": "", "license": "MIT", "dependencies": { - "@popperjs/core": "^2.11.2" + "@popperjs/core": "^2.11.2", + "xregexp": "^5.1.1" }, "devDependencies": { "@types/jest": "^28.1.8", diff --git a/src/components/RegExpBackslash.ts b/src/components/RegExpBackslash.ts index 1b5c42f..46ae0cf 100644 --- a/src/components/RegExpBackslash.ts +++ b/src/components/RegExpBackslash.ts @@ -1,4 +1,4 @@ -export const createBackslash = (textContent = '=> => => =>') => { +export const createBackslash = (textContent = '/') => { const previewLabel = window.document.createElement('div'); previewLabel.className = 'bulk_regexp_slash'; previewLabel.textContent = textContent; diff --git a/src/constants/RegExpFlags.ts b/src/constants/RegExpFlags.ts index e44d0ff..76a3057 100644 --- a/src/constants/RegExpFlags.ts +++ b/src/constants/RegExpFlags.ts @@ -1,26 +1,15 @@ -export type RegExpFlag = - | 'g' - | 'm' - | 'i' - | 'x' - | 's' - | 'u' - | 'U' - | 'A' - | 'J' - | 'D'; +export type RegExpFlag = 'g' | 'i' | 'm' | 'u' | 'y' | 'n' | 's' | 'x' | 'A'; export const REGEXP_FLAGS = [ 'g', - 'm', 'i', - 'x', - 's', + 'm', 'u', - 'U', + 'y', + 'n', + 's', + 'x', 'A', - 'J', - 'D', ] as const; export type RegExpFlags = typeof REGEXP_FLAGS; diff --git a/src/services/file.service.ts b/src/services/file.service.ts index 400e4ec..2b10a2c 100644 --- a/src/services/file.service.ts +++ b/src/services/file.service.ts @@ -1,5 +1,6 @@ import { App, Notice, TFile } from 'obsidian'; import BulkRenamePlugin from '../../main'; +import XRegExp from 'xregexp'; export const getFilesNamesInDirectory = (plugin: BulkRenamePlugin) => { const { fileNames } = plugin.settings; @@ -77,9 +78,6 @@ export const renameFilesInObsidian = async ( new Notice('successfully renamed all files'); }; -let reRegExpChar = /[\\^$.*+?()[\]{}]/g, - reHasRegExpChar = RegExp(reRegExpChar.source); - export function escapeRegExp(s: string) { - return s && reHasRegExpChar.test(s) ? s.replace(reRegExpChar, '\\$&') : s; + return XRegExp.escape(s); } diff --git a/src/services/obsidian.service.ts b/src/services/obsidian.service.ts index d715fa3..ec38006 100644 --- a/src/services/obsidian.service.ts +++ b/src/services/obsidian.service.ts @@ -1,5 +1,6 @@ import { App, TFile } from 'obsidian'; import BulkRenamePlugin from '../../main'; +import XRegExp from 'xregexp'; export const getObsidianFilesByFolderName = ( app: App, @@ -21,14 +22,19 @@ export const getObsidianFilesByRegExp = ( app: App, plugin: BulkRenamePlugin, ) => { - const { userRegExp } = plugin.settings; + const { regExpState } = plugin.settings; + + const regExp = XRegExp(regExpState.regExp, regExpState.flags.join('')); + const abstractFiles = app.vault.getAllLoadedFiles(); - const files = abstractFiles.filter( - (file) => file instanceof TFile && file.parent.name.includes(userRegExp), - ) as TFile[]; + const matchedFileNames = abstractFiles.filter((file) => { + if (file instanceof TFile && XRegExp.match(file.path, regExp)) { + return true; + } + }) as TFile[]; - const filesSortedByName = sortFilesByName(files); + const filesSortedByName = sortFilesByName(matchedFileNames); return filesSortedByName; }; diff --git a/src/suggestions/RegExpFlagsSuggest.ts b/src/suggestions/RegExpFlagsSuggest.ts index eace9a5..ac95cfc 100644 --- a/src/suggestions/RegExpFlagsSuggest.ts +++ b/src/suggestions/RegExpFlagsSuggest.ts @@ -34,9 +34,6 @@ export class RegExpFlagsSuggest extends TextInputSuggest { } target.classList.toggle('bulk-flag-selected'); this.inputEl.value = regExpState.flags.join(''); - // this.inputEl.trigger('input'); - // this.settings.plugin.settings.regExpState.flags.push(file); - // this.inputEl.trigger('input'); - // this.close(); + this.inputEl.trigger('input'); }; } From e4d9d7ac4aff30e58cd6412eabe05764fa95c431 Mon Sep 17 00:00:00 2001 From: Oleh Lustenko Date: Sun, 18 Sep 2022 09:25:38 +0300 Subject: [PATCH 4/5] revert back escapeRegExp --- src/services/file.service.ts | 6 ++++-- src/suggestions/RegExpFlagsSuggest.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/services/file.service.ts b/src/services/file.service.ts index 2b10a2c..400e4ec 100644 --- a/src/services/file.service.ts +++ b/src/services/file.service.ts @@ -1,6 +1,5 @@ import { App, Notice, TFile } from 'obsidian'; import BulkRenamePlugin from '../../main'; -import XRegExp from 'xregexp'; export const getFilesNamesInDirectory = (plugin: BulkRenamePlugin) => { const { fileNames } = plugin.settings; @@ -78,6 +77,9 @@ export const renameFilesInObsidian = async ( new Notice('successfully renamed all files'); }; +let reRegExpChar = /[\\^$.*+?()[\]{}]/g, + reHasRegExpChar = RegExp(reRegExpChar.source); + export function escapeRegExp(s: string) { - return XRegExp.escape(s); + return s && reHasRegExpChar.test(s) ? s.replace(reRegExpChar, '\\$&') : s; } diff --git a/src/suggestions/RegExpFlagsSuggest.ts b/src/suggestions/RegExpFlagsSuggest.ts index ac95cfc..3f75f4c 100644 --- a/src/suggestions/RegExpFlagsSuggest.ts +++ b/src/suggestions/RegExpFlagsSuggest.ts @@ -4,7 +4,7 @@ import { TextInputSuggest } from './suggest'; import { REGEXP_FLAGS, RegExpFlag } from '../constants/RegExpFlags'; export class RegExpFlagsSuggest extends TextInputSuggest { - // @ts-ignore TODO refactor types types + // @ts-ignore TODO refactor types getSuggestions() { return REGEXP_FLAGS; } From e8fc01fb332208a620d4fa57e19ee2c866cedada Mon Sep 17 00:00:00 2001 From: Oleh Lustenko Date: Sun, 18 Sep 2022 09:36:10 +0300 Subject: [PATCH 5/5] improve wording of description --- main.ts | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/main.ts b/main.ts index 10e1bf7..9202588 100644 --- a/main.ts +++ b/main.ts @@ -186,6 +186,7 @@ export class BulkRenameSettingsTab extends PluginSettingTab { if (!isViewTypeTags(this.plugin)) { return; } + new Setting(this.containerEl) .setName('Tag names ') .setDesc('all files with the tags will be found') @@ -217,9 +218,17 @@ export class BulkRenameSettingsTab extends PluginSettingTab { if (!isViewTypeRegExp(this.plugin)) { return; } + + const desc = document.createDocumentFragment(); + desc.append( + desc.createEl('b', { + text: 'Reg exp will match file Operation System path', + }), + ); + new Setting(this.containerEl) - .setName('RegExp') - .setDesc('all files by titles will be found') + .setName('RegExp Search') + .setDesc(desc) .addText((cb) => { const backslash = createBackslash('/'); cb.inputEl.insertAdjacentElement('beforebegin', backslash); @@ -330,7 +339,7 @@ export class BulkRenameSettingsTab extends PluginSettingTab { renderRenameFiles() { const desc = document.createDocumentFragment(); desc.append( - 'You are going to update all marked files and their directories', + 'You are going to update all files from preview section', desc.createEl('br'), desc.createEl('b', { text: 'Warning: ',