diff --git a/README.md b/README.md index bb533b1..f72704b 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,14 @@ This is a plugin for [Obsidian](https://obsidian.md/) that adds the command `Sma 1. Adds the previous title as an alias to the renamed note 2. Preserves the backlinks to the renamed note that were using previous title as a display text. +## Demo vault + +A demo vault with usage examples ships with every release. You can access it via any of the following: + +1. Running the **Smart Rename: Open demo vault** command. +2. Downloading `smart-rename.demo-vault.zip` from the [Releases](https://github.com/mnaoumov/obsidian-smart-rename/releases). +3. Browsing its source in [`demo-vault/`](./demo-vault/README.md) in this repository. + ## Detailed explanation ### Step 1 diff --git a/demo-vault/.gitignore b/demo-vault/.gitignore new file mode 100644 index 0000000..1273035 --- /dev/null +++ b/demo-vault/.gitignore @@ -0,0 +1,13 @@ +# Churny / runtime-generated Obsidian state. +.obsidian/workspace.json +.obsidian/hotkeys.json + +# Built plugins are release-injected by archivePluginDemoVault at release time — +# both the plugin under test AND the obsidian-dev-utils-owned Demo Vault Helper +# bootstrap plugin (which installs, configures, and enables CodeScript Toolkit at +# runtime). Nothing helper-related is committed; commit only the baked settings +# file for the plugin under test. +.obsidian/plugins/* +!.obsidian/plugins/smart-rename/ +.obsidian/plugins/smart-rename/* +!.obsidian/plugins/smart-rename/data.json diff --git a/demo-vault/.markdownlint-cli2.jsonc b/demo-vault/.markdownlint-cli2.jsonc new file mode 100644 index 0000000..bb807df --- /dev/null +++ b/demo-vault/.markdownlint-cli2.jsonc @@ -0,0 +1,12 @@ +{ + // Scoped markdownlint config for the demo vault. The notes are an Obsidian + // vault, so two default rules are inherently incompatible and disabled here; + // every other rule still applies so the notes stay clean. + "config": { + // Notes intentionally open with a `[Docs](...)` link, not a heading. + "MD041": false, + // `[[wikilinks]]` are Obsidian's native link syntax; markdownlint parses + // them as undefined shortcut reference links. + "MD052": false + } +} diff --git a/demo-vault/.obsidian/app.json b/demo-vault/.obsidian/app.json new file mode 100644 index 0000000..e13f1f9 --- /dev/null +++ b/demo-vault/.obsidian/app.json @@ -0,0 +1,8 @@ +{ + "attachmentFolderPath": "_assets/attachments", + "newLinkFormat": "shortest", + "useMarkdownLinks": false, + "showUnsupportedFiles": true, + "defaultViewMode": "source", + "livePreview": true +} diff --git a/demo-vault/.obsidian/community-plugins.json b/demo-vault/.obsidian/community-plugins.json new file mode 100644 index 0000000..3cc9feb --- /dev/null +++ b/demo-vault/.obsidian/community-plugins.json @@ -0,0 +1,4 @@ +[ + "demo-vault-helper", + "smart-rename" +] diff --git a/demo-vault/00 Start.md b/demo-vault/00 Start.md new file mode 100644 index 0000000..e88ce26 --- /dev/null +++ b/demo-vault/00 Start.md @@ -0,0 +1,18 @@ +Welcome to the [Smart Rename](https://github.com/mnaoumov/obsidian-smart-rename/) demo vault. When you rename a note, Obsidian normally rewrites every link to point at the new name - and the visible text changes with it. **Smart Rename** instead preserves the old title as the link's display text, so your notes keep reading the way you wrote them. It also handles invalid characters, the first header, and a frontmatter title key. + +**How to try it:** open [[Rename me]], run **Smart Rename: Invoke** from the Command Palette (or right-click the note and choose the smart rename option), and type a new title. Then look at [[References/Note A]] and [[References/Note B]] - the links still show the old title. + +> [!TIP] Interactive buttons +> +> The two setup notes have **Run** buttons, powered by [`CodeScript Toolkit`](https://github.com/mnaoumov/obsidian-codescript-toolkit/), which this vault installs for you automatically on first open (see [[CodeScript Toolkit prerequisite]]). Renaming itself is a manual command, so the feature notes have no buttons. + +## Feature + +- [[Smart rename]] +- [[Invalid characters]] +- [[Settings]] + +## Setup + +- [[Code buttons check]] +- [[CodeScript Toolkit prerequisite]] diff --git a/demo-vault/Code buttons check.md b/demo-vault/Code buttons check.md new file mode 100644 index 0000000..4ebeb04 --- /dev/null +++ b/demo-vault/Code buttons check.md @@ -0,0 +1,13 @@ +[Docs](https://github.com/mnaoumov/obsidian-codescript-toolkit/) + +# Code buttons check + +If [`CodeScript Toolkit`](https://github.com/mnaoumov/obsidian-codescript-toolkit/) is installed and enabled, the block below renders as a **Run** button. Click it - a notice should appear. If you only see a code block, install the prerequisite first: [[CodeScript Toolkit prerequisite]]. + +```code-button +--- +caption: Click me +--- +import { Notice } from 'obsidian'; +new Notice('Code buttons work - you are ready to explore the demo vault.'); +``` diff --git a/demo-vault/CodeScript Toolkit prerequisite.md b/demo-vault/CodeScript Toolkit prerequisite.md new file mode 100644 index 0000000..518fa47 --- /dev/null +++ b/demo-vault/CodeScript Toolkit prerequisite.md @@ -0,0 +1,22 @@ +[Docs](https://github.com/mnaoumov/obsidian-codescript-toolkit/) + +# CodeScript Toolkit prerequisite + +The **Run** buttons in this vault are powered by [`CodeScript Toolkit`](https://github.com/mnaoumov/obsidian-codescript-toolkit/). This vault installs and enables it for you automatically the first time you open the vault (and trust it). Nothing here is required to explore Smart Rename - renaming is a plain command with no button. + +## If the buttons do not work + +If a code block does not turn into a button, install CodeScript Toolkit manually: + +1. Open **Settings -> Community plugins -> Browse**. +2. Search for **CodeScript Toolkit**, install it, and enable it. +3. Reopen a note that has a **Run** button. + +Or click the button below to install and enable it (needs an internet connection): + +```code-button +--- +caption: Install CodeScript Toolkit +--- +await require('/demoSetup.ts').installAndEnable(app, 'fix-require-modules'); +``` diff --git a/demo-vault/Invalid characters.md b/demo-vault/Invalid characters.md new file mode 100644 index 0000000..53f77bf --- /dev/null +++ b/demo-vault/Invalid characters.md @@ -0,0 +1,19 @@ +[Docs](https://github.com/mnaoumov/obsidian-smart-rename/) + +# Invalid characters + +Some characters (like `:` `/` `\` `*` `?`) cannot appear in a file name. Smart Rename lets you decide what happens when your new title contains one. + +## Try it + +1. Open [[Rename me]] and run **Smart Rename: Invoke**. +2. Type a title that contains an invalid character, such as `Chapter 1: Beginnings`. +3. Depending on the **Invalid characters action** setting, Smart Rename will either show an error, remove the invalid character, or replace it. + +## The three actions + +- **Error** - refuse the rename and show a notice (the default). +- **Remove** - strip the invalid characters from the file name. +- **Replace** - swap each invalid character for the configured replacement character (default `_`). + +When the invalid title is stored as the note's display text (so the reader still sees `Chapter 1: Beginnings` even though the file name is sanitized) is controlled by the store-invalid-title setting. See [[Settings]] for all of these keys. diff --git a/demo-vault/README.md b/demo-vault/README.md new file mode 100644 index 0000000..c310ad1 --- /dev/null +++ b/demo-vault/README.md @@ -0,0 +1,9 @@ +# Smart Rename demo vault + +A small Obsidian vault that demonstrates the [Smart Rename](https://github.com/mnaoumov/obsidian-smart-rename) plugin - it renames the active note and rewrites its backlinks so their display text keeps showing the old title, with control over invalid characters, the first header, and a frontmatter title key. + +Open [00 Start](<./00 Start.md>) and work through the notes. Open [Rename me](<./Rename me.md>), run **Smart Rename: Invoke**, and watch the backlinks in `References/`. + +## First open + +The first time you open this vault, Obsidian treats it as **untrusted**, so the bundled plugins are listed but not loaded until you **Trust author and enable plugins** and reload. After that, the Demo Vault Helper installs [CodeScript Toolkit](https://github.com/mnaoumov/obsidian-codescript-toolkit) (which powers the optional **Run** buttons in the setup notes) and opens the start note for you. diff --git a/demo-vault/References/Note A.md b/demo-vault/References/Note A.md new file mode 100644 index 0000000..78254f7 --- /dev/null +++ b/demo-vault/References/Note A.md @@ -0,0 +1,5 @@ +[Docs](https://github.com/mnaoumov/obsidian-smart-rename/) + +# Note A + +A note that links to [[Rename me]] with a plain link (no alias). After a smart rename, this becomes `[[New title|Rename me]]` so it still reads "Rename me". diff --git a/demo-vault/References/Note B.md b/demo-vault/References/Note B.md new file mode 100644 index 0000000..e97eae9 --- /dev/null +++ b/demo-vault/References/Note B.md @@ -0,0 +1,5 @@ +[Docs](https://github.com/mnaoumov/obsidian-smart-rename/) + +# Note B + +Another note linking to [[Rename me|our starting note]]. It already has a custom alias, so the link keeps showing "our starting note" - smart rename only swaps the target, never your chosen display text. diff --git a/demo-vault/Rename me.md b/demo-vault/Rename me.md new file mode 100644 index 0000000..9ffb92e --- /dev/null +++ b/demo-vault/Rename me.md @@ -0,0 +1,7 @@ +[Docs](https://github.com/mnaoumov/obsidian-smart-rename/) + +# Rename me + +This is the note the [[Smart rename]] demo renames. With this note active, run **Smart Rename: Invoke** and give it a new title. + +Two notes link here - [[References/Note A]] and [[References/Note B]]. After the rename, their links will keep showing "Rename me" as their display text instead of switching to the new name. diff --git a/demo-vault/Settings.md b/demo-vault/Settings.md new file mode 100644 index 0000000..376a99a --- /dev/null +++ b/demo-vault/Settings.md @@ -0,0 +1,25 @@ +[Docs](https://github.com/mnaoumov/obsidian-smart-rename/) + +# Settings + +Open **Settings -> Community plugins -> Smart Rename** to configure the plugin. Each option below lists the setting key stored in the plugin's `data.json`. + +## Invalid characters + +- `invalidCharacterAction` - how to process invalid characters in the new title: show an error, remove them, or replace them. +- `replacementCharacter` - the character used to replace invalid characters (only when the action is *Replace*). +- `shouldStoreInvalidTitle` - keep the original, invalid title as the note's display text; if disabled, the sanitized version is stored. + +## Title + +- `shouldUpdateFirstHeader` - also update the first header of the note when it matches the old title. +- `shouldUpdateTitleKey` - update the `title` key in the note's frontmatter. + +## Previous display text + +- `shouldPreservePreviousDisplayTextInNoteLinks` - keep the old title as display text in ordinary note links. +- `shouldPreservePreviousDisplayTextInFrontmatterLinks` - keep the old title as display text in links inside frontmatter. + +## Other + +- `shouldSupportNonMarkdownFiles` - make the command and context menu available for non-markdown files too. diff --git a/demo-vault/Smart rename.md b/demo-vault/Smart rename.md new file mode 100644 index 0000000..c0128c7 --- /dev/null +++ b/demo-vault/Smart rename.md @@ -0,0 +1,20 @@ +[Docs](https://github.com/mnaoumov/obsidian-smart-rename/) + +# Smart rename + +Smart Rename renames the **active note** and rewrites its backlinks so their **display text keeps showing the old title**. A plain rename would change the visible link text to the new name; Smart Rename turns `[[Old title]]` into `[[New title|Old title]]` so the reader still sees what you originally wrote. + +## Try it + +1. Open [[Rename me]] (the note this demo renames). +2. Run **Smart Rename: Invoke** from the Command Palette, or right-click the note in the file explorer and choose the smart rename option. +3. Type a new title - for example `Renamed note` - and confirm. +4. Open [[References/Note A]] and [[References/Note B]]. Their links now point at the new note, but still **display** the old title. + +## What it preserves + +- **Note links** - a bare `[[Rename me]]` becomes `[[Renamed note|Rename me]]`, keeping the old text visible (controlled by the note-links setting in [[Settings]]). +- **Frontmatter links** - links inside YAML frontmatter get the same treatment (controlled by the frontmatter-links setting). +- **The first header and a title key** - optionally kept in sync with the new name (see [[Settings]]). + +Renaming to a title that contains characters Obsidian cannot use in a filename is handled separately - see [[Invalid characters]]. diff --git a/demo-vault/_assets/CodeScriptToolkit/demoSetup.ts b/demo-vault/_assets/CodeScriptToolkit/demoSetup.ts new file mode 100644 index 0000000..5b25fc7 --- /dev/null +++ b/demo-vault/_assets/CodeScriptToolkit/demoSetup.ts @@ -0,0 +1,16 @@ +import type { App } from 'obsidian'; + +import { Notice } from 'obsidian'; +import { + enableCommunityPlugin, + installCommunityPlugin +} from 'obsidian-dev-utils/obsidian/community-plugins'; + +// Smart Rename works on the active file via a command + a prompt for the new title, so there is +// Nothing for a code-button to drive - the demo notes walk through it manually. The only helper the +// Vault needs is the shared CodeScript Toolkit installer used by the prerequisite note's button. +export async function installAndEnable(app: App, pluginId: string): Promise { + await installCommunityPlugin({ app, pluginId }); + await enableCommunityPlugin({ app, pluginId }); + new Notice(`Installed and enabled: ${pluginId}`); +} diff --git a/demo-vault/_assets/CodeScriptToolkit/startup.ts b/demo-vault/_assets/CodeScriptToolkit/startup.ts new file mode 100644 index 0000000..dc13a1c --- /dev/null +++ b/demo-vault/_assets/CodeScriptToolkit/startup.ts @@ -0,0 +1,10 @@ +// Per-vault startup script, run by the universal Demo Vault Helper plugin (via CodeScript +// Toolkit's require) once CodeScript Toolkit is installed and enabled. This is where each +// plugin's demo vault does its own startup setup. Here it just opens the landing note. + +const START_NOTE_PATH = '00 Start.md'; + +const startNote = app.vault.getFileByPath(START_NOTE_PATH); +if (startNote) { + void app.workspace.getLeaf(false).openFile(startNote); +} diff --git a/dprint.json b/dprint.json new file mode 100644 index 0000000..6981058 --- /dev/null +++ b/dprint.json @@ -0,0 +1,10 @@ +{ + "extends": "./node_modules/obsidian-dev-utils/dist/templates/dprint.json", + "excludes": [ + "dist", + "**/node_modules", + "**/*-lock.json", + "**/*.md", + "demo-vault" + ] +} diff --git a/src/demo-vault.no-app.integration.test.ts b/src/demo-vault.no-app.integration.test.ts new file mode 100644 index 0000000..0dd9cf6 --- /dev/null +++ b/src/demo-vault.no-app.integration.test.ts @@ -0,0 +1,21 @@ +import process from 'node:process'; +import { registerDemoVaultCoverageSuite } from 'obsidian-dev-utils/script-utils/demo-vault-coverage'; +import { getRootFolder } from 'obsidian-dev-utils/script-utils/root'; + +// Keeps the in-repo `demo-vault/` in sync with the plugin's public surface WITHOUT +// Launching Obsidian: it reflects the real config from source and asserts every +// Setting is documented in a note, and that the guard note/member still exist +// (rename drift). Smart Rename's feature surface is an editor/file command with +// No public API interface, so only the PluginSettings config class is reflected; +// The plugin's runtime behavior is covered by the other integration tests. +registerDemoVaultCoverageSuite({ + configInterfaces: [{ interfaceName: 'PluginSettings', sourcePath: 'src/plugin-settings.ts' }], + interfaces: [], + nonTrivialGuard: { + expectDemoNote: 'Settings.md', + expectMember: 'invalidCharacterAction', + interfaceName: 'PluginSettings', + sourcePath: 'src/plugin-settings.ts' + }, + rootFolder: getRootFolder() ?? process.cwd() +});