mirror of
https://github.com/mnaoumov/obsidian-smart-rename.git
synced 2026-07-22 07:40:32 +00:00
Refactor
This commit is contained in:
parent
1f333d68d9
commit
d26056e403
6 changed files with 275 additions and 1334 deletions
1356
package-lock.json
generated
1356
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -16,10 +16,10 @@
|
|||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@tsconfig/strictest": "^2.0.5",
|
||||
"@types/node": "^22.8.7",
|
||||
"@types/node": "^22.9.0",
|
||||
"obsidian": "^1.7.2",
|
||||
"obsidian-dev-utils": "^4.0.0",
|
||||
"obsidian-typings": "^2.2.1-beta.34"
|
||||
"obsidian-dev-utils": "^4.4.0",
|
||||
"obsidian-typings": "^2.3.0"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,24 @@
|
|||
import type {
|
||||
CachedMetadata,
|
||||
LinkCache
|
||||
LinkCache,
|
||||
PluginSettingTab
|
||||
} from 'obsidian';
|
||||
import {
|
||||
Notice,
|
||||
parseFrontMatterAliases,
|
||||
Plugin,
|
||||
Platform,
|
||||
TFile
|
||||
} from 'obsidian';
|
||||
import type { MaybePromise } from 'obsidian-dev-utils/Async';
|
||||
import { invokeAsyncSafely } from 'obsidian-dev-utils/Async';
|
||||
import { PluginBase } from 'obsidian-dev-utils/obsidian/Plugin/PluginBase';
|
||||
|
||||
import { InvalidCharacterAction } from './InvalidCharacterAction.ts';
|
||||
import prompt from './prompt.ts';
|
||||
import SmartRenameSettings from './SmartRenameSettings.ts';
|
||||
import SmartRenameSettingsTab from './SmartRenameSettingsTab.ts';
|
||||
import SmartRenamePluginSettings from './SmartRenamePluginSettings.ts';
|
||||
import SmartRenamePluginSettingsTab from './SmartRenamePluginSettingsTab.ts';
|
||||
|
||||
export default class SmartRenamePlugin extends Plugin {
|
||||
export default class SmartRenamePlugin extends PluginBase<SmartRenamePluginSettings> {
|
||||
private systemForbiddenCharactersRegExp!: RegExp;
|
||||
private readonly obsidianForbiddenCharactersRegExp = /[#^[\]|]/g;
|
||||
private currentNoteFile!: TFile;
|
||||
|
|
@ -24,11 +27,16 @@ export default class SmartRenamePlugin extends Plugin {
|
|||
private newPath!: string;
|
||||
private readonly backlinksToFix: Map<string, Set<number>> = new Map<string, Set<number>>();
|
||||
private isReadyToFixBacklinks!: boolean;
|
||||
public settings!: SmartRenameSettings;
|
||||
|
||||
public override async onload(): Promise<void> {
|
||||
await this.loadSettings();
|
||||
protected override createDefaultPluginSettings(): SmartRenamePluginSettings {
|
||||
return new SmartRenamePluginSettings();
|
||||
}
|
||||
|
||||
protected override createPluginSettingsTab(): PluginSettingTab | null {
|
||||
return new SmartRenamePluginSettingsTab(this);
|
||||
}
|
||||
|
||||
protected override onloadComplete(): MaybePromise<void> {
|
||||
this.addCommand({
|
||||
id: 'smart-rename',
|
||||
name: 'Smart Rename',
|
||||
|
|
@ -39,15 +47,13 @@ export default class SmartRenamePlugin extends Plugin {
|
|||
}
|
||||
|
||||
if (!checking) {
|
||||
void this.smartRename(activeFile);
|
||||
invokeAsyncSafely(() => this.smartRename(activeFile));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
this.addSettingTab(new SmartRenameSettingsTab(this.app, this));
|
||||
|
||||
const isWindows = document.body.hasClass('mod-windows');
|
||||
const isWindows = Platform.isWin;
|
||||
this.systemForbiddenCharactersRegExp = isWindows ? /[*"\\/<>:|?]/g : /[\\/]/g;
|
||||
|
||||
this.registerEvent(this.app.metadataCache.on('resolved', () => {
|
||||
|
|
@ -246,14 +252,6 @@ export default class SmartRenamePlugin extends Plugin {
|
|||
this.backlinksToFix.clear();
|
||||
}
|
||||
|
||||
private async loadSettings(): Promise<void> {
|
||||
this.settings = Object.assign(new SmartRenameSettings(), await this.loadData() as SmartRenameSettings | undefined);
|
||||
}
|
||||
|
||||
public async saveSettings(): Promise<void> {
|
||||
await this.saveData(this.settings);
|
||||
}
|
||||
|
||||
public hasInvalidCharacters(str: string): boolean {
|
||||
return this.systemForbiddenCharactersRegExp.test(str) || this.obsidianForbiddenCharactersRegExp.test(str);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { InvalidCharacterAction } from './InvalidCharacterAction.ts';
|
||||
|
||||
export default class SmartRenameSettings {
|
||||
export default class SmartRenamePluginSettings {
|
||||
public invalidCharacterAction = InvalidCharacterAction.Error;
|
||||
public replacementCharacter = '_';
|
||||
public shouldStoreInvalidTitle = true;
|
||||
84
src/SmartRenamePluginSettingsTab.ts
Normal file
84
src/SmartRenamePluginSettingsTab.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import { Setting } from 'obsidian';
|
||||
import { PluginSettingsTabBase } from 'obsidian-dev-utils/obsidian/Plugin/PluginSettingsTabBase';
|
||||
import { extend } from 'obsidian-dev-utils/obsidian/Plugin/ValueComponent';
|
||||
|
||||
import { InvalidCharacterAction } from './InvalidCharacterAction.ts';
|
||||
import type SmartRenamePlugin from './SmartRenamePlugin.ts';
|
||||
|
||||
export default class SmartRenamePluginSettingsTab extends PluginSettingsTabBase<SmartRenamePlugin> {
|
||||
public display(): void {
|
||||
this.containerEl.empty();
|
||||
|
||||
new Setting(this.containerEl)
|
||||
.setName('Invalid characters action')
|
||||
.setDesc('How to process invalid characters in the new title')
|
||||
.addDropdown((dropdown) => {
|
||||
dropdown
|
||||
.addOptions({
|
||||
Error: 'Show error',
|
||||
Remove: 'Remove invalid characters',
|
||||
Replace: 'Replace invalid character with'
|
||||
});
|
||||
extend(dropdown)
|
||||
.bind(this.plugin, 'invalidCharacterAction', {
|
||||
onChanged: () => { this.display(); }
|
||||
});
|
||||
});
|
||||
|
||||
if (this.plugin.settingsCopy.invalidCharacterAction === InvalidCharacterAction.Replace) {
|
||||
new Setting(this.containerEl)
|
||||
.setName('Replacement character')
|
||||
.setDesc('Character to replace invalid character with')
|
||||
.addText((text) => {
|
||||
text.inputEl.maxLength = 1;
|
||||
text.inputEl.required = true;
|
||||
|
||||
extend(text)
|
||||
.bind(this.plugin, 'replacementCharacter', {
|
||||
valueValidator: (value) => {
|
||||
if (this.plugin.hasInvalidCharacters(value)) {
|
||||
return 'Invalid replacement character';
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (this.plugin.settingsCopy.invalidCharacterAction !== InvalidCharacterAction.Error) {
|
||||
new Setting(this.containerEl)
|
||||
.setName('Store invalid title')
|
||||
.setDesc('If enabled, stores title with invalid characters. If disabled, stores the sanitized version')
|
||||
.addToggle((toggle) =>
|
||||
extend(toggle)
|
||||
.bind(this.plugin, 'shouldStoreInvalidTitle')
|
||||
);
|
||||
}
|
||||
|
||||
new Setting(this.containerEl)
|
||||
.setName('Update title key')
|
||||
.setDesc('Update title key in frontmatter')
|
||||
.addToggle((toggle) =>
|
||||
extend(toggle)
|
||||
.bind(this.plugin, 'shouldUpdateTitleKey')
|
||||
);
|
||||
|
||||
new Setting(this.containerEl)
|
||||
.setName('Update first header')
|
||||
.setDesc(createFragment((f) => {
|
||||
f.appendText('Update first header if it is present in the document. May conflict with the ');
|
||||
f.createEl('a', {
|
||||
attr: {
|
||||
href: 'https://obsidian.md/plugins?id=obsidian-filename-heading-sync'
|
||||
},
|
||||
text: 'Filename Heading Sync'
|
||||
});
|
||||
f.appendText(' plugin.');
|
||||
}))
|
||||
.addToggle((toggle) =>
|
||||
extend(toggle)
|
||||
.bind(this.plugin, 'shouldUpdateFirstHeader')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
import {
|
||||
App,
|
||||
PluginSettingTab,
|
||||
Setting
|
||||
} from 'obsidian';
|
||||
|
||||
import { InvalidCharacterAction } from './InvalidCharacterAction.ts';
|
||||
import type SmartRenamePlugin from './SmartRenamePlugin.ts';
|
||||
|
||||
export default class SmartRenameSettingsTab extends PluginSettingTab {
|
||||
public override plugin: SmartRenamePlugin;
|
||||
|
||||
public constructor(app: App, plugin: SmartRenamePlugin) {
|
||||
super(app, plugin);
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
public display(): void {
|
||||
const { containerEl } = this;
|
||||
containerEl.empty();
|
||||
containerEl.createEl('h2', { text: 'Smart Rename' });
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Invalid characters action')
|
||||
.setDesc('How to process invalid characters in the new title')
|
||||
.addDropdown((dropdownComponent) => {
|
||||
dropdownComponent
|
||||
.addOptions({
|
||||
Error: 'Show error',
|
||||
Remove: 'Remove invalid characters',
|
||||
Replace: 'Replace invalid character with'
|
||||
})
|
||||
.setValue(this.plugin.settings.invalidCharacterAction)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.invalidCharacterAction = InvalidCharacterAction[value as keyof typeof InvalidCharacterAction];
|
||||
await this.plugin.saveSettings();
|
||||
this.renderReplacementCharacterSettingEl(replacementCharacterSettingEl);
|
||||
this.renderStoreInvalidTitleSettingEl(storeInvalidTitleSettingEl);
|
||||
});
|
||||
|
||||
const replacementCharacterSettingEl = containerEl.createDiv();
|
||||
this.renderReplacementCharacterSettingEl(replacementCharacterSettingEl);
|
||||
|
||||
const storeInvalidTitleSettingEl = containerEl.createDiv();
|
||||
this.renderStoreInvalidTitleSettingEl(storeInvalidTitleSettingEl);
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Update title key')
|
||||
.setDesc('Update title key in frontmatter')
|
||||
.addToggle((toggleComponent) => {
|
||||
toggleComponent
|
||||
.setValue(this.plugin.settings.shouldUpdateTitleKey)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.shouldUpdateTitleKey = value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Update first header')
|
||||
.setDesc('Update first header if it is present in the document. May conflict with the `Filename Heading Sync` plugin')
|
||||
.addToggle((toggleComponent) => {
|
||||
toggleComponent
|
||||
.setValue(this.plugin.settings.shouldUpdateFirstHeader)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.shouldUpdateFirstHeader = value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private renderReplacementCharacterSettingEl(replacementCharacterSettingEl: HTMLDivElement): void {
|
||||
replacementCharacterSettingEl.empty();
|
||||
|
||||
if (this.plugin.settings.invalidCharacterAction === InvalidCharacterAction.Replace) {
|
||||
new Setting(replacementCharacterSettingEl)
|
||||
.setName('Replacement character')
|
||||
.setDesc('Character to replace invalid character with')
|
||||
.addText((textComponent) => {
|
||||
textComponent.inputEl.maxLength = 1;
|
||||
textComponent.inputEl.required = true;
|
||||
textComponent.inputEl.addEventListener('blur', () => {
|
||||
textComponent.inputEl.reportValidity();
|
||||
});
|
||||
textComponent
|
||||
.setValue(this.plugin.settings.replacementCharacter)
|
||||
.onChange(async (value) => {
|
||||
if (this.plugin.hasInvalidCharacters(value)) {
|
||||
textComponent.inputEl.setCustomValidity('Invalid replacement character');
|
||||
} else {
|
||||
textComponent.inputEl.setCustomValidity('');
|
||||
}
|
||||
|
||||
if (textComponent.inputEl.reportValidity()) {
|
||||
this.plugin.settings.replacementCharacter = value;
|
||||
await this.plugin.saveSettings();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private renderStoreInvalidTitleSettingEl(storeInvalidTitleSettingEl: HTMLDivElement): void {
|
||||
storeInvalidTitleSettingEl.empty();
|
||||
|
||||
if (this.plugin.settings.invalidCharacterAction === InvalidCharacterAction.Error) {
|
||||
return;
|
||||
}
|
||||
|
||||
new Setting(storeInvalidTitleSettingEl)
|
||||
.setName('Store invalid title')
|
||||
.setDesc('If enabled, stores title with invalid characters. If disabled, stores the sanitized version')
|
||||
.addToggle((toggleComponent) => {
|
||||
toggleComponent
|
||||
.setValue(this.plugin.settings.shouldStoreInvalidTitle)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.shouldStoreInvalidTitle = value;
|
||||
await this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue