diff --git a/docs/src/settings.md b/docs/src/settings.md index 8730a983..3870fa4d 100644 --- a/docs/src/settings.md +++ b/docs/src/settings.md @@ -1,27 +1,58 @@ # Settings -You can set a `Template folder location` to tell [Templater](https://github.com/SilentVoid13/Templater) to only check this folder for templates. +## General Settings -You can set a timeout for your system commands with the `Timeout` option. A system command that takes longer than what you defined will be canceled and considered as a failure. +- `Template folder location`: Files in this folder will be available as templates. +- `Syntax Highlighting on Desktop` adds syntax highlighting for [Templater](https://github.com/SilentVoid13/Templater) commands in edit mode. +- `Syntax Highlighting on Mobile` adds syntax highlighting for [Templater](https://github.com/SilentVoid13/Templater) commands in edit mode on mobile. Use with caution: this may break live preview on mobile platforms." +- `Automatic jump to cursor` automatically triggers `tp.file.cursor` after inserting a template. You can also set a hotkey to manually trigger `tp.file.cursor`. +- `Trigger Templater on new file creation`: [Templater](https://github.com/SilentVoid13/Templater) will listen for the new file creation event, and, if it matches a rule you've set, replace every command it finds in the new file's content. This makes [Templater](https://github.com/SilentVoid13/Templater) compatible with other plugins like the Daily note core plugin, Calendar plugin, Review plugin, Note refactor plugin, etc. + - Make sure to set up rules under either Folder Templates or File Regex Template below. + - **Warning:** This can be dangerous if you create new files with unknown / unsafe content on creation. Make sure that every new file's content is safe on creation." +- `Show icon in sidebar`: Show [Templater](https://github.com/SilentVoid13/Templater) icon in sidebar ribbon, allowing you to quickly use templates anywhere. -You can set [Templater](https://github.com/SilentVoid13/Templater) to be triggered on new file creation. It will listen for the new file creation event and replace every command it finds in the new file's content. +## Template Hotkeys -This makes Templater compatible with other plugins like the Daily note core plugin, Calendar plugin, Review plugin, Note refactor plugin, ... +Template Hotkeys allows you to bind a template to a hotkey. -## Security Warning +## Folder Templates -It can be dangerous if you create new files with unknown / unsafe content on creation. Make sure that every new file's content is safe on creation. +**Note**: This setting is hidden by default. To view it first enable the `Trigger Template on new file creation` setting. And since it's mutually exclusive with File Regex Templates, enabling one will disable the other. -## Folder Templates +You can specify a template that will automatically be used on a selected folder and children using the `Folder Templates` functionality. The deepest match will be used, so the order of the rules is irrelevant. + +Add a rule for "`/`" if you need a catch-all. + +## File Regex Templates + +**Note**: This setting is hidden by default. To view it first enable the `Trigger Template on new file creation` setting. And since it's mutually exclusive with Folder Templates, enabling one will disable the other. + +You can specify regex declarations that a new file's path will be tested against. If a regex matches, the associated template will automatically be used. Rules are tested top-to-bottom, and the first match will be used. + +End with a rule for "`.*`" if you need a catch-all. + +Use a tool like [Regex101](https://regex101.com/) to verify your regexes. + +## Startup Templates + +Startup Templates are templates that will get executed once when Templater starts. + +These templates won't output anything. + +This can be useful to set up templates adding hooks to obsidian events for example. + +## User Script Functions + +All JavaScript files in this folder will be loaded as CommonJS modules, to import custom [user functions](./user-functions/overview.md). -You can specify a template that will automatically be used on a selected folder and children using the `Folder Templates` functionality. +The folder needs to be accessible from the vault. -**Note**: This setting is hidden by default. To view it first enable the `Trigger Template on new file creation` setting. +Check the [documentation](./user-functions/script-user-functions.md) for more information. -## System Commands +## User System Command Functions -You can enable system commands. This allows you to create [user functions](./user-functions/overview.md) linked to system commands. +Allows you to create [user functions](./user-functions/overview.md) linked to system commands. -### Arbitrary system commands +Check the [documentation](./user-functions/system-user-functions.md) for more information. -It can be dangerous to execute arbitrary system commands from untrusted sources. Only run system commands that you understand, from trusted sources. +**Warning:** It can be dangerous to execute arbitrary system commands from untrusted sources. Only run system commands that you understand, from trusted sources. diff --git a/src/core/Templater.ts b/src/core/Templater.ts index bf38ac54..4b7cb2d2 100644 --- a/src/core/Templater.ts +++ b/src/core/Templater.ts @@ -443,6 +443,17 @@ export class Templater { } while (folder); } + get_new_file_template_for_file(file: TFile): string | undefined { + const match = this.plugin.settings.file_templates.find((e) => { + const eRegex = new RegExp(e.regex); + return eRegex.test(file.path); + }); + + if (match && match.template) { + return match.template; + } + } + static async on_file_creation( templater: Templater, file: TAbstractFile @@ -488,6 +499,26 @@ export class Templater { return; } await templater.write_template_to_file(template_file, file); + } else if ( + file.stat.size == 0 && + templater.plugin.settings.enable_file_templates + ) { + const file_template_match = + templater.get_new_file_template_for_file(file); + if (!file_template_match) { + return; + } + const template_file: TFile = await errorWrapper( + async (): Promise => { + return resolve_tfile(file_template_match); + }, + `Couldn't find template ${file_template_match}` + ); + // errorWrapper failed + if (template_file == null) { + return; + } + await templater.write_template_to_file(template_file, file); } else { if (file.stat.size <= 100000) { //https://github.com/SilentVoid13/Templater/issues/873 diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 9f07751d..eae38909 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -11,6 +11,11 @@ export interface FolderTemplate { template: string; } +export interface FileTemplate { + regex: string; + template: string; +} + export const DEFAULT_SETTINGS: Settings = { command_timeout: 5, templates_folder: "", @@ -22,6 +27,8 @@ export const DEFAULT_SETTINGS: Settings = { user_scripts_folder: "", enable_folder_templates: true, folder_templates: [{ folder: "", template: "" }], + enable_file_templates: false, + file_templates: [{ regex: ".*", template: "" }], syntax_highlighting: true, syntax_highlighting_mobile: false, enabled_templates_hotkeys: [""], @@ -39,6 +46,8 @@ export interface Settings { user_scripts_folder: string; enable_folder_templates: boolean; folder_templates: Array; + enable_file_templates: boolean; + file_templates: Array; syntax_highlighting: boolean; syntax_highlighting_mobile: boolean; enabled_templates_hotkeys: Array; @@ -60,6 +69,7 @@ export class TemplaterSettingTab extends PluginSettingTab { this.add_trigger_on_new_file_creation_setting(); if (this.plugin.settings.trigger_on_file_creation) { this.add_folder_templates_setting(); + this.add_file_templates_setting(); } this.add_templates_hotkeys_setting(); this.add_startup_templates_setting(); @@ -174,9 +184,12 @@ export class TemplaterSettingTab extends PluginSettingTab { add_trigger_on_new_file_creation_setting(): void { const desc = document.createDocumentFragment(); desc.append( - "Templater will listen for the new file creation event, and replace every command it finds in the new file's content.", + "Templater will listen for the new file creation event, and, if it matches a rule you've set, replace every command it finds in the new file's content. ", + "This makes Templater compatible with other plugins like the Daily note core plugin, Calendar plugin, Review plugin, Note refactor plugin, etc. ", + desc.createEl("br"), + desc.createEl("br"), + "Make sure to set up rules under either Folder Templates or File Regex Template below.", desc.createEl("br"), - "This makes Templater compatible with other plugins like the Daily note core plugin, Calendar plugin, Review plugin, Note refactor plugin, ...", desc.createEl("br"), desc.createEl("b", { text: "Warning: ", @@ -343,7 +356,7 @@ export class TemplaterSettingTab extends PluginSettingTab { const descUseNewFileTemplate = document.createDocumentFragment(); descUseNewFileTemplate.append( - "When enabled Templater will make use of the folder templates defined below." + "When enabled, Templater will make use of the folder templates defined below. This option is mutually exclusive with File Regex Templates below, so enabling one will disable the other." ); new Setting(this.containerEl) @@ -352,9 +365,12 @@ export class TemplaterSettingTab extends PluginSettingTab { .addToggle((toggle) => { toggle .setValue(this.plugin.settings.enable_folder_templates) - .onChange((use_new_file_templates) => { + .onChange((use_new_folder_templates) => { this.plugin.settings.enable_folder_templates = - use_new_file_templates; + use_new_folder_templates; + if (use_new_folder_templates) { + this.plugin.settings.enable_file_templates = false; + } this.plugin.save_settings(); // Force refresh this.display(); @@ -469,6 +485,138 @@ export class TemplaterSettingTab extends PluginSettingTab { }); } + add_file_templates_setting(): void { + this.containerEl.createEl("h2", { text: "File Regex Templates" }); + + const descHeading = document.createDocumentFragment(); + descHeading.append( + "File Regex Templates are triggered when a new ", + descHeading.createEl("strong", { text: "empty" }), + " file is created that matches one of them. Templater will fill the empty file with the specified template." + ); + + new Setting(this.containerEl).setDesc(descHeading); + + const descUseNewFileTemplate = document.createDocumentFragment(); + descUseNewFileTemplate.append( + "When enabled, Templater will make use of the file regex templates defined below. This option is mutually exclusive with Folder Templates above, so enabling one will disable the other." + ); + + new Setting(this.containerEl) + .setName("Enable File Regex Templates") + .setDesc(descUseNewFileTemplate) + .addToggle((toggle) => { + toggle + .setValue(this.plugin.settings.enable_file_templates) + .onChange((use_new_file_templates) => { + this.plugin.settings.enable_file_templates = + use_new_file_templates; + if (use_new_file_templates) { + this.plugin.settings.enable_folder_templates = + false; + } + this.plugin.save_settings(); + // Force refresh + this.display(); + }); + }); + + if (!this.plugin.settings.enable_file_templates) { + return; + } + + new Setting(this.containerEl) + .setName("Add New") + .setDesc( + "Add new file regex. The first match from the top is used, so the order of the rules is important. Use `.*` as a final catch-all, if you need it." + ) + .addButton((button: ButtonComponent) => { + button + .setTooltip("Add additional file regex") + .setButtonText("+") + .setCta() + .onClick(() => { + this.plugin.settings.file_templates.push({ + regex: "", + template: "", + }); + this.plugin.save_settings(); + this.display(); + }); + }); + + this.plugin.settings.file_templates.forEach((file_template, index) => { + const s = new Setting(this.containerEl) + .addText((cb) => { + cb.setPlaceholder("File Regex") + .setValue(file_template.regex) + .onChange((new_regex) => { + this.plugin.settings.file_templates[index].regex = + new_regex; + this.plugin.save_settings(); + }); + // @ts-ignore + cb.inputEl.addClass("templater_search"); + }) + .addSearch((cb) => { + new FileSuggest( + cb.inputEl, + this.plugin, + FileSuggestMode.TemplateFiles + ); + cb.setPlaceholder("Template") + .setValue(file_template.template) + .onChange((new_template) => { + this.plugin.settings.file_templates[ + index + ].template = new_template; + this.plugin.save_settings(); + }); + // @ts-ignore + cb.containerEl.addClass("templater_search"); + }) + .addExtraButton((cb) => { + cb.setIcon("up-chevron-glyph") + .setTooltip("Move up") + .onClick(() => { + arraymove( + this.plugin.settings.file_templates, + index, + index - 1 + ); + this.plugin.save_settings(); + this.display(); + }); + }) + .addExtraButton((cb) => { + cb.setIcon("down-chevron-glyph") + .setTooltip("Move down") + .onClick(() => { + arraymove( + this.plugin.settings.file_templates, + index, + index + 1 + ); + this.plugin.save_settings(); + this.display(); + }); + }) + .addExtraButton((cb) => { + cb.setIcon("cross") + .setTooltip("Delete") + .onClick(() => { + this.plugin.settings.file_templates.splice( + index, + 1 + ); + this.plugin.save_settings(); + this.display(); + }); + }); + s.infoEl.remove(); + }); + } + add_startup_templates_setting(): void { new Setting(this.containerEl).setName("Startup templates").setHeading();