feat: add posibilty to put RegExp to Existing and Replacement + styles improvements
This commit is contained in:
parent
e6ba6e88e3
commit
6ea539162b
61
main.ts
61
main.ts
|
@ -34,6 +34,7 @@ export interface BulkRenamePluginSettings {
|
|||
tags: string[];
|
||||
regExpState: {
|
||||
regExp: string;
|
||||
withRegExpForReplaceSymbols: boolean;
|
||||
flags: RegExpFlag[];
|
||||
};
|
||||
viewType: 'tags' | 'folder' | 'regexp';
|
||||
|
@ -47,6 +48,7 @@ const DEFAULT_SETTINGS: BulkRenamePluginSettings = {
|
|||
regExpState: {
|
||||
regExp: '',
|
||||
flags: [],
|
||||
withRegExpForReplaceSymbols: false,
|
||||
},
|
||||
tags: [],
|
||||
viewType: 'folder',
|
||||
|
@ -269,20 +271,48 @@ export class BulkRenameSettingsTab extends PluginSettingTab {
|
|||
.controlEl.addClass('bulk_regexp_control');
|
||||
}
|
||||
|
||||
renderUseRegExpForExistingAndReplacement() {
|
||||
if (!isViewTypeRegExp(this.plugin.settings)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newSettings2 = new Setting(this.containerEl);
|
||||
|
||||
newSettings2
|
||||
.setName('Use RegExp For Existing & Replacement?')
|
||||
.setDesc(
|
||||
"Only RegExp will work now, however it doesn't prevent you to pass string",
|
||||
)
|
||||
.addToggle((toggle) => {
|
||||
toggle
|
||||
.setValue(
|
||||
this.plugin.settings.regExpState.withRegExpForReplaceSymbols,
|
||||
)
|
||||
.setTooltip('Use RegExp For Existing & Replacement?')
|
||||
.onChange((isRegExpForNames) => {
|
||||
this.plugin.settings.regExpState.withRegExpForReplaceSymbols =
|
||||
isRegExpForNames;
|
||||
this.reRenderPreview();
|
||||
this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
renderReplaceSymbol() {
|
||||
const { settings } = this.plugin;
|
||||
|
||||
this.renderUseRegExpForExistingAndReplacement();
|
||||
const newSettings = new Setting(this.containerEl);
|
||||
newSettings.infoEl.style.display = 'none';
|
||||
|
||||
newSettings.addText((textComponent) => {
|
||||
if (Platform.isDesktop) {
|
||||
const previewLabel = createPreviewElement('Existing');
|
||||
textComponent.inputEl.insertAdjacentElement(
|
||||
'beforebegin',
|
||||
previewLabel,
|
||||
);
|
||||
}
|
||||
if (Platform.isDesktop) {
|
||||
const previewLabel = createPreviewElement('Existing');
|
||||
const replacementLabel = createPreviewElement('Replacement');
|
||||
newSettings.infoEl.replaceChildren(previewLabel, replacementLabel);
|
||||
newSettings.setClass('flex');
|
||||
newSettings.setClass('flex-col');
|
||||
newSettings.infoEl.addClass('bulk_info');
|
||||
}
|
||||
newSettings.controlEl.addClass('replaceRenderSymbols');
|
||||
newSettings.addTextArea((textComponent) => {
|
||||
textComponent.setValue(settings.existingSymbol);
|
||||
textComponent.setPlaceholder('existing chars');
|
||||
textComponent.onChange((newValue) => {
|
||||
|
@ -293,14 +323,7 @@ export class BulkRenameSettingsTab extends PluginSettingTab {
|
|||
textComponent.inputEl.onblur = this.reRenderPreview;
|
||||
});
|
||||
|
||||
newSettings.addText((textComponent) => {
|
||||
if (Platform.isDesktop) {
|
||||
const previewLabel = createPreviewElement('Replacement');
|
||||
textComponent.inputEl.insertAdjacentElement(
|
||||
'beforebegin',
|
||||
previewLabel,
|
||||
);
|
||||
}
|
||||
newSettings.addTextArea((textComponent) => {
|
||||
textComponent.setValue(settings.replacePattern);
|
||||
textComponent.setPlaceholder('replace with');
|
||||
textComponent.onChange((newValue) => {
|
||||
|
@ -323,7 +346,7 @@ export class BulkRenameSettingsTab extends PluginSettingTab {
|
|||
text: `Total Files: ${this.plugin.settings.fileNames.length}`,
|
||||
});
|
||||
|
||||
this.filesAndPreview.infoEl.style.display = 'none';
|
||||
this.filesAndPreview.infoEl.detach();
|
||||
|
||||
this.filesAndPreview.controlEl.addClass('bulk_rename_preview');
|
||||
this.reRenderPreview();
|
||||
|
|
|
@ -52,6 +52,7 @@ export const syncScrolls = (
|
|||
) => {
|
||||
existingFilesArea.addEventListener('scroll', (event) => {
|
||||
const target = event.target as HTMLTextAreaElement;
|
||||
|
||||
if (target.scrollTop !== state.previewScroll) {
|
||||
previewArea.scrollTop = target.scrollTop;
|
||||
state.previewScroll = target.scrollTop;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { App, Notice, TFile } from 'obsidian';
|
||||
import XRegExp from 'xregexp';
|
||||
import BulkRenamePlugin, { BulkRenamePluginSettings } from '../../main';
|
||||
import { isViewTypeFolder } from './settings.service';
|
||||
import { ROOT_FOLDER_NAME } from '../constants/folders';
|
||||
|
@ -49,16 +50,24 @@ export const selectFilenamesWithReplacedPath = (plugin: BulkRenamePlugin) => {
|
|||
|
||||
export const replaceFilePath = (plugin: BulkRenamePlugin, file: TFile) => {
|
||||
const pathWithoutExtension = file.path.split('.').slice(0, -1).join('.');
|
||||
const { replacePattern, existingSymbol } = plugin.settings;
|
||||
const { replacePattern, existingSymbol, regExpState } = plugin.settings;
|
||||
|
||||
if (isRootFilesSelected(plugin)) {
|
||||
const newPath = replacePattern + pathWithoutExtension;
|
||||
return `${newPath}.${file.extension}`;
|
||||
}
|
||||
|
||||
const convertedToRegExpString = escapeRegExp(existingSymbol);
|
||||
const regExpSymbol = new RegExp(convertedToRegExpString, 'g');
|
||||
const newPath = pathWithoutExtension?.replace(regExpSymbol, replacePattern);
|
||||
let regExpExistingSymbol: RegExp | string = existingSymbol;
|
||||
if (regExpState.withRegExpForReplaceSymbols) {
|
||||
regExpExistingSymbol = XRegExp(existingSymbol, 'x');
|
||||
}
|
||||
|
||||
const newPath = XRegExp.replace(
|
||||
pathWithoutExtension,
|
||||
regExpExistingSymbol,
|
||||
replacePattern,
|
||||
'all',
|
||||
);
|
||||
|
||||
return `${newPath}.${file.extension}`;
|
||||
};
|
||||
|
@ -102,13 +111,6 @@ export const renameFilesInObsidian = async (
|
|||
success && 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;
|
||||
}
|
||||
|
||||
const isRootFilesSelected = (plugin: BulkRenamePlugin) => {
|
||||
const { existingSymbol, folderName } = plugin.settings;
|
||||
|
||||
|
|
|
@ -28,6 +28,9 @@ describe('File Services', () => {
|
|||
settings: {
|
||||
replacePattern: '-',
|
||||
existingSymbol: '_',
|
||||
regExpState: {
|
||||
withRegExpForReplaceSymbols: false,
|
||||
},
|
||||
},
|
||||
} as unknown as BulkRenamePlugin;
|
||||
|
||||
|
@ -48,6 +51,9 @@ describe('File Services', () => {
|
|||
settings: {
|
||||
replacePattern: '-',
|
||||
existingSymbol: '.',
|
||||
regExpState: {
|
||||
withRegExpForReplaceSymbols: false,
|
||||
},
|
||||
},
|
||||
} as unknown as BulkRenamePlugin;
|
||||
|
||||
|
@ -68,6 +74,9 @@ describe('File Services', () => {
|
|||
settings: {
|
||||
replacePattern: 'days',
|
||||
existingSymbol: 'journals',
|
||||
regExpState: {
|
||||
withRegExpForReplaceSymbols: false,
|
||||
},
|
||||
},
|
||||
} as unknown as BulkRenamePlugin;
|
||||
|
||||
|
@ -106,6 +115,9 @@ describe('File Services', () => {
|
|||
const mockPluginPlugin = {
|
||||
settings: {
|
||||
fileNames: files,
|
||||
regExpState: {
|
||||
withRegExpForReplaceSymbols: false,
|
||||
},
|
||||
},
|
||||
} as unknown as BulkRenamePlugin;
|
||||
|
||||
|
@ -116,6 +128,9 @@ describe('File Services', () => {
|
|||
...mockPluginPlugin.settings,
|
||||
existingSymbol: 'journals|pages|bulkRenameTets|canWe',
|
||||
replacePattern: 'qwe',
|
||||
regExpState: {
|
||||
withRegExpForReplaceSymbols: true,
|
||||
},
|
||||
},
|
||||
} as unknown as BulkRenamePlugin;
|
||||
|
||||
|
@ -157,6 +172,99 @@ describe('File Services', () => {
|
|||
|
||||
expect(files).toEqual(updatedFiles);
|
||||
});
|
||||
|
||||
it('should rename many files using capture groups', () => {
|
||||
const plugin = {
|
||||
...mockPluginPlugin,
|
||||
settings: {
|
||||
...mockPluginPlugin.settings,
|
||||
existingSymbol: '2022_(.+)',
|
||||
replacePattern: '$1_2022',
|
||||
regExpState: {
|
||||
withRegExpForReplaceSymbols: true,
|
||||
},
|
||||
},
|
||||
} as unknown as BulkRenamePlugin;
|
||||
|
||||
const expectedResults = [
|
||||
{
|
||||
path: 'journals/10_13_2022.md',
|
||||
extension: 'md',
|
||||
},
|
||||
{
|
||||
path: 'pages/10_13_2022.md',
|
||||
extension: 'md',
|
||||
},
|
||||
{
|
||||
path: 'bulkRenameTets/10_13_2022.md',
|
||||
extension: 'md',
|
||||
},
|
||||
{
|
||||
path: 'YesWecan/canWe/10_13_2022.md',
|
||||
extension: 'md',
|
||||
},
|
||||
];
|
||||
|
||||
const updatedFiles = selectFilenamesWithReplacedPath(plugin);
|
||||
|
||||
expect(expectedResults).toEqual(updatedFiles);
|
||||
});
|
||||
|
||||
it('should rename many files using capture groups', () => {
|
||||
const files = [
|
||||
{
|
||||
path: '2022_10_13.md',
|
||||
extension: 'md',
|
||||
},
|
||||
{
|
||||
path: '2022_10_14.md',
|
||||
extension: 'md',
|
||||
},
|
||||
{
|
||||
path: '2022_10_15.md',
|
||||
extension: 'md',
|
||||
},
|
||||
{
|
||||
path: '2022_10_16.md',
|
||||
extension: 'md',
|
||||
},
|
||||
] as unknown as TFile[];
|
||||
const plugin = {
|
||||
settings: {
|
||||
fileNames: files,
|
||||
existingSymbol: `(?<year> [0-9]{4} ) _? # year
|
||||
(?<month> [0-9]{2} ) _? # month
|
||||
(?<day> [0-9]{2} ) # day`,
|
||||
replacePattern: '$<month>-$<day>-$<year>',
|
||||
regExpState: {
|
||||
withRegExpForReplaceSymbols: true,
|
||||
},
|
||||
},
|
||||
} as unknown as BulkRenamePlugin;
|
||||
|
||||
const expectedResults = [
|
||||
{
|
||||
path: '10-13-2022.md',
|
||||
extension: 'md',
|
||||
},
|
||||
{
|
||||
path: '10-14-2022.md',
|
||||
extension: 'md',
|
||||
},
|
||||
{
|
||||
path: '10-15-2022.md',
|
||||
extension: 'md',
|
||||
},
|
||||
{
|
||||
path: '10-16-2022.md',
|
||||
extension: 'md',
|
||||
},
|
||||
];
|
||||
|
||||
const updatedFiles = selectFilenamesWithReplacedPath(plugin);
|
||||
|
||||
expect(expectedResults).toEqual(updatedFiles);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
41
styles.css
41
styles.css
|
@ -8,10 +8,38 @@
|
|||
gap: 0;
|
||||
}
|
||||
|
||||
.flex {
|
||||
display: flex;
|
||||
}
|
||||
.flex-col {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.m-auto {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.bulk_info {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.bulk_rename_preview > textarea {
|
||||
height: 360px;
|
||||
}
|
||||
|
||||
.replaceRenderSymbols {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding-top: 1rem;
|
||||
}
|
||||
|
||||
.setting-item-control .bulk_preview_textarea {
|
||||
min-width: 19em;
|
||||
}
|
||||
|
||||
.bulk_preview_textarea {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
|
@ -19,9 +47,6 @@
|
|||
width: 100%;
|
||||
height: 400px;
|
||||
resize: none;
|
||||
width: 100%;
|
||||
/*white-space: nowrap;*/
|
||||
/*overflow: auto;*/
|
||||
}
|
||||
|
||||
.bulk_button {
|
||||
|
@ -33,12 +58,18 @@
|
|||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.bulk_input {
|
||||
.setting-item-control .bulk_input {
|
||||
width: 100%;
|
||||
resize: none;
|
||||
min-width: auto;
|
||||
min-height: auto;
|
||||
}
|
||||
|
||||
.setting-item-control .bulk_input:first-child {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
.bulk_preview_label {
|
||||
.bulk_preview_label:first-child {
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue