From eca0d7da33829f804a9a2452d6d98a5ac16c9bf7 Mon Sep 17 00:00:00 2001 From: Kodai Nakamura Date: Wed, 5 Feb 2025 19:49:41 +0900 Subject: [PATCH] feat: add minimum character count setting --- README.md | 8 +++++++- src/main.ts | 1 + src/replace-links.ts | 24 ++++++++++++++++++++++++ src/settings.ts | 23 +++++++++++++++++++++++ 4 files changed, 55 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 05f23f4..bd9db03 100644 --- a/README.md +++ b/README.md @@ -8,11 +8,14 @@ Automatic Linker Plugin automatically converts plain text file references into O The plugin scans your file for text that matches file names in your vault and converts them into wiki links by wrapping them in `[[ ]]`. - **Format on Save:** - Optionally, the plugin can automatically format (i.e. convert links) when you save your file. + Optionally, the plugin can automatically format (i.e. convert links) when you save a file. - **Configurable Base Directories:** Specify directories (e.g. `pages`) that are treated as base. For files in these directories, the directory prefix can be omitted when linking. +- **Minimum Character Count:** + If the file content is shorter than the specified minimum character count, link conversion is skipped. This prevents accidental formatting of very short texts. + - **Respects Existing Links:** Already formatted links (i.e. those wrapped in `[[ ]]`) are preserved and not reformatted. @@ -36,3 +39,6 @@ The plugin settings are available under the **Automatic Linker Plugin** settings - **Base Directories:** Enter one or more directory names (one per line) that should be treated as base. For example, if you enter `pages`, then file links like `pages/tags` can be referenced simply as `tags`. + +- **Minimum Character Count:** + Set the minimum number of characters required for the file content to be processed. If the file content is shorter than this value, link conversion will be skipped. diff --git a/src/main.ts b/src/main.ts index 0d5ff24..91c01d9 100644 --- a/src/main.ts +++ b/src/main.ts @@ -74,6 +74,7 @@ export default class AutomaticLinkerPlugin extends Plugin { fileContent, trie: this.trie ?? buildCandidateTrie([]).trie, candidateMap: this.candidateMap ?? new Map(), + minCharCount: this.settings.minCharCount, getFrontMatterInfo, }); diff --git a/src/replace-links.ts b/src/replace-links.ts index 4ec39b4..28b56e8 100644 --- a/src/replace-links.ts +++ b/src/replace-links.ts @@ -7,19 +7,28 @@ import { buildCandidateTrie, TrieNode } from "./trie"; * @param trie - The pre-built Trie for candidate lookup. * @param candidateMap - Mapping from candidate string to its canonical replacement. * @param getFrontMatterInfo - Function to get the front matter info. + * @param minCharCount - Minimum character count required to perform replacement. * @returns The file content with replaced links. */ export const replaceLinks = async ({ fileContent, trie, candidateMap, + minCharCount = 0, getFrontMatterInfo, }: { fileContent: string; trie: TrieNode; candidateMap: Map; + minCharCount?: number; getFrontMatterInfo: (fileContent: string) => { contentStart: number }; }): Promise => { + // If the file content is shorter than the minimum character count, + // return the content unchanged. + if (fileContent.length <= minCharCount) { + return fileContent; + } + // Helper: determine if a character is a word boundary. const isWordBoundary = (char: string | undefined): boolean => { if (char === undefined) return true; @@ -140,6 +149,7 @@ if (import.meta.vitest) { trie, candidateMap, getFrontMatterInfo, + minCharCount: 0, }), ).toBe("[[hello]]"); }); @@ -670,5 +680,19 @@ if (import.meta.vitest) { }), ).toBe("```typescript\nexample\n```"); }); + it("skips replacement when content is too short", async () => { + const fileNames = getSortedFileNames(["hello"]); + const { candidateMap, trie } = buildCandidateTrie(fileNames); + // When minCharCount is higher than the fileContent length, no replacement should occur. + expect( + await replaceLinks({ + fileContent: "hello", + trie, + candidateMap, + getFrontMatterInfo, + minCharCount: 10, + }), + ).toBe("hello"); + }); }); } diff --git a/src/settings.ts b/src/settings.ts index b816a42..5504a7a 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -5,12 +5,14 @@ export type AutomaticLinkerSettings = { formatOnSave: boolean; baseDirs: string[]; showNotice: boolean; + minCharCount: number; // Minimum character count setting }; export const DEFAULT_SETTINGS: AutomaticLinkerSettings = { formatOnSave: false, baseDirs: ["pages"], showNotice: false, + minCharCount: 0, // Default value: 0 (always replace links) }; export class AutomaticLinkerPluginSettingsTab extends PluginSettingTab { @@ -39,6 +41,7 @@ export class AutomaticLinkerPluginSettingsTab extends PluginSettingTab { }); }); + // Setting for base directories. new Setting(containerEl) .setName("Base Directories") .setDesc( @@ -56,6 +59,7 @@ export class AutomaticLinkerPluginSettingsTab extends PluginSettingTab { }); }); + // Toggle for showing the load notice. new Setting(containerEl) .setName("Show Load Notice") .setDesc("Display a notice when markdown files are loaded.") @@ -67,5 +71,24 @@ export class AutomaticLinkerPluginSettingsTab extends PluginSettingTab { await this.plugin.saveData(this.plugin.settings); }); }); + + // Setting for minimum character count. + // If the text is below this number of characters, links will not be replaced. + new Setting(containerEl) + .setName("Minimum Character Count") + .setDesc( + "If the content is below this character count, the links will not be replaced.", + ) + .addText((text) => { + text.setPlaceholder("e.g. 4") + .setValue(this.plugin.settings.minCharCount.toString()) + .onChange(async (value) => { + const parsedValue = parseInt(value); + if (!isNaN(parsedValue)) { + this.plugin.settings.minCharCount = parsedValue; + await this.plugin.saveData(this.plugin.settings); + } + }); + }); } }