# Obsidian Punctilious Normalize Markdown punctuation: convert Chinese punctuation to English punctuation, add spaces between Chinese and English/digits, and leave URLs inside links untouched. English | [中文](README-zh.md) ## Features - **Spaces around numbers**: `共100元` → `共 100 元` - **Spaces between Chinese and English**: `使用TypeScript开发` → `使用 TypeScript 开发` - **Chinese punctuation to English**: `你好,世界。` → `你好, 世界.` - **Automatic spacing after converted punctuation** - **Ideographic comma to comma**: `苹果、香蕉` → `苹果, 香蕉` - **Dashes and book title marks are preserved**: `——`, `《》` - **URLs in links are exempt**: addresses inside Markdown links, images, Wiki links and bare URLs are never modified - **Safe zones are protected**: code blocks, inline code, math, HTML tags and comments, YAML frontmatter - **Two scopes**: format the whole note, or just the selected text ## Installation ### Manual installation 1. Download `main.js`, `manifest.json` and `styles.css` from the latest release 2. Create a `punctilious` folder inside your vault's `.obsidian/plugins/` 3. Copy the downloaded files into that folder 4. Reload Obsidian and enable the plugin in **Settings → Community plugins** ## Usage 1. Open a Markdown note 2. Press `Ctrl/Cmd + P` to open the command palette 3. Run one of the following commands: | Command | Description | |---------|-------------| | Normalize punctuation in current note | Formats the entire active note | | Normalize punctuation in selection | Formats only the selected text; formats the whole note when nothing is selected | ## Formatting rules ### 1. Spaces around numbers | Before | After | |--------|-------| | `共100元` | `共 100 元` | | `总共3个苹果和12个梨` | `总共 3 个苹果和 12 个梨` | | `2026年是重要的一年` | `2026 年是重要的一年` | | `- 2026年计划` | `- 2026 年计划` | No leading space is added when the number sits at the beginning of a paragraph or a line. ### 2. Spaces between Chinese and English | Before | After | |--------|-------| | `使用TypeScript开发` | `使用 TypeScript 开发` | | `这是一个Obsidian插件` | `这是一个 Obsidian 插件` | No leading space is added when the English text sits at the beginning of a paragraph or a line. No space is inserted between English and digits (`iPhone15`, `v1.2.3` stay as they are). > Existing spaces are never duplicated: `使用 TypeScript 开发` stays unchanged, and runs of multiple spaces collapse into one. When only one side has a space, just the missing side is filled in (for example `共 100元` → `共 100 元`). ### 3. Chinese punctuation to English punctuation A space is added **after** the converted punctuation. Opening brackets and quotes get the space **before** them instead, and any redundant space before a closing mark is removed. | Before | After | |--------|-------| | `你好,世界。今天怎么样?` | `你好, 世界. 今天怎么样?` | | `第一项;第二项:第三项` | `第一项; 第二项: 第三项` | | `我(你)好` | `我 (你) 好` | | `中文(English)结尾` | `中文 (English) 结尾` | | `他说:“你好!”` | `他说: "你好!"` | | `等等……还有` | `等等... 还有` | Full conversion table: | Chinese | English | |---------|---------| | `,` | `, ` | | `。` | `. ` | | `、` | `, ` (can be disabled in settings) | | `;` | `; ` | | `:` | `: ` | | `?` | `? ` | | `!` | `! ` | | `( )` | ` ( ` / `) ` | | `【 】` | ` [ ` / `] ` | | `〔 〕`, `〖 〗` | ` [ ` / `] ` | | `〈 〉` | ` < ` / `> ` | | `“ ”`, `「 」` | ` "` / `" ` | | `‘ ’`, `『 』` | ` '` / `' ` | | `~` | `~` | | `……` | `... ` | | `——` | preserved | | `《 》` | preserved | ### 4. URLs in links are exempt URLs are never modified and never get extra spaces: ```markdown 参见[链接](https://example.com/docs?a=1&b=2#中文)与[[笔记/2026计划|我的计划]]。 ``` becomes: ```markdown 参见[链接](https://example.com/docs?a=1&b=2#中文)与[[笔记/2026计划|我的计划]]. ``` Exempt content also includes image URLs, reference-style link definitions, `` autolinks, bare URLs and Wiki link targets. ### 5. Zones preserved as-is - YAML frontmatter - Fenced code blocks (``` / `~~~`) and inline code (`` ` ``) - Math (`$$...$$` / `$...$`) - HTML tags and HTML comments - Obsidian comments (`%%...%%`) - Markdown block markers (indentation, blockquotes, headings, lists, task lists, footnote definitions) and hard line breaks (two trailing spaces) ## Settings Open **Settings → Punctilious** to tune the rules. | Setting | Default | Description | |---------|---------|-------------| | Add spaces between Chinese and English/digits | On | No space is added at the start of a line | | Convert Chinese punctuation to English | On | Dashes and book title marks are always preserved | | Add a space after punctuation | On | Adds a space after the converted punctuation | | Convert ideographic comma to comma | On | Turn off to keep `、` as-is | | Skip code blocks and math | On | Code and math are left untouched | | Skip URLs in links | On | Link addresses are left untouched | | Skip YAML frontmatter | On | Frontmatter is left untouched | | Show completion notice | On | Shows a notice when formatting finishes | ## Requirements - Obsidian v1.6.6 or later - Works on desktop and mobile ## Security & privacy - Fully offline: no network requests at all - Only reads and writes the note you are working on; never scans or uploads vault content - No telemetry and no user data collection - All settings are stored locally in `data.json` ## Development ```bash # Install dependencies npm install # Build in watch mode npm run dev # Production build npm run build # Lint npm run lint ``` ## Continuous integration The project ships with two GitHub Actions workflows: | Workflow | Trigger | Description | |----------|---------|-------------| | `.github/workflows/lint.yml` | Push and pull request on any branch | Runs `npm ci`, `npm run build` and `npm run lint` on Node.js 20.x / 22.x | | `.github/workflows/release.yml` | Tag push | Builds the plugin and uploads `main.js`, `manifest.json`, `styles.css` and a zip archive as release assets | ### Releasing a new version `npm version` runs `version-bump.mjs`, which keeps `manifest.json` and `versions.json` in sync: ```bash npm version patch # or minor / major git push --follow-tags ``` Pushing the tag triggers the release workflow. The tag must match the `version` in `manifest.json` exactly (no leading `v`). ## License [MIT](LICENSE)