PunctFlow

approved

by Che-Year

标点流 — 中文 Markdown 智能标点转换:在中文输入法下输入中文标点(如 ·)时自动转换为对应的英文 Markdown 标点(如反引号 `),支持上下文感知、反引号自动配对与批量转换。 - This plugin has not been manually reviewed by Obsidian staff.

1 stars31 downloadsUpdated 29d agoMIT

PunctFlow

中文版本

PunctFlow is an Obsidian plugin that intelligently converts Chinese punctuation to the corresponding English Markdown punctuation while you type under a Chinese input method — most importantly · (interpunct) → ` (backtick) — reducing the cost of switching between Chinese and English input methods. Core design principles: smart, controllable, and never harmful.

It is an upgraded, generalized version of the dot-to-backtick plugin (which replaces the Chinese interpunct · with a backtick `), extended into a universal smart converter for Chinese punctuation.

✨ Features

FeatureDescription
🔧 Configurable mapping tableDefault ·`; add, edit, or remove any mapping in the settings (empty target = delete the character)
🧠 Context awarenessNo conversion inside code blocks, inline code, math formulas, URLs, link text, or frontmatter; Chinese personal-name interpuncts (卡尔·马克思) are never converted
⚡ Backtick auto-pairingTyping · inserts a pair of backticks and places the cursor between them; typing · again skips past the closing backtick so duplicates never appear
🖥 Batch conversion commandsConvert selection / current line / whole document (selection falls back to the current line when nothing is selected)
🎛 Three working modesRealtime mode (default) / manual mode / paste conversion
🚫 Exclusion rulesExclude files by folder path or file extension; frontmatter is not converted by default
↩️ Undo mergingEach conversion produces a single transaction, so one Ctrl+Z undoes it

📦 Installation

  1. Build the plugin (requires Node.js ≥ 18):
    npm install
    npm run build
    
  2. Copy the project folder into <your-vault>/.obsidian/plugins/punctflow/ (make sure it contains main.js, manifest.json, and styles.css).
  3. In Obsidian, open Settings → Community plugins, and enable PunctFlow.

Plugin ID: punctflow.

⚙️ Configuration

Open Settings → PunctFlow settings:

  1. Punctuation mapping table: each entry is a "source character → target string". Leaving the target empty deletes the character. Rules are matched from top to bottom (the first hit wins). Use + Add mapping to add, the trash icon to delete, or Reset mappings to restore ·`.
  2. Auto-pair backticks: when enabled, typing · inserts a pair of backticks with the cursor centered; typing · again skips past an existing closing backtick.
  3. Working mode:
    • Realtime (default): converts immediately as you type a mapped character;
    • Manual: never auto-converts; conversion happens only through commands;
    • Paste conversion: converts pasted content automatically after a paste.
  4. Excluded folders: one path per line (relative to the vault root, e.g. journal); files inside these folders are not converted.
  5. Excluded file extensions: one per line without the dot (e.g. txt); files with these extensions are not converted.

🎮 Usage

  • Realtime input: with a Chinese input method active, type · (usually the backtick key) and the plugin turns it into ` with auto-pairing; mapped characters such as or behave the same way (depending on your mapping table).
  • Command palette (Ctrl/Cmd + P):
    • PunctFlow: Convert selection (falls back to the current line when nothing is selected)
    • PunctFlow: Convert current line
    • PunctFlow: Convert whole document
  • Paste conversion: switch the working mode to "Paste conversion", then pasted content is converted automatically.

Typical flow (backtick auto-pairing)

  1. Type · at the cursor → `` is inserted and the cursor is placed between the backticks;
  2. Type your code → `code`;
  3. Type · once more → the cursor skips past the closing backtick, no duplicate backticks.

Scenarios that are never converted (auto-detected)

```js
// The · inside code blocks is not converted
const a = '卡尔·马克思';   // Chinese personal-name interpuncts are not converted

The · inside inline code is not converted, $The · inside math is not converted$, link text · not converted.

---
title: The · inside frontmatter is not converted
---

🧠 How it works

1. Context awareness

Before converting, three levels of checks run (by priority):

  1. Line scanning: scans from the start of the file to determine whether the current line is inside frontmatter (------) or a fenced code block (``` / ~~~);
  2. CodeMirror 6 syntax tree: the plugin reads the editor's internal CM6 state through a minimal structured interface and resolves the node at the cursor position with tree.resolveInner(offset), then walks up the parent chain. If the node name matches code / math / url / link / image / html / comment / frontmatter and similar, conversion is skipped (special case: if the character right after the cursor is a backtick — the user is closing an inline code span — conversion is allowed);
  3. Inline heuristics (fallback when the syntax tree is unavailable):
    • Both sides of the cursor are Chinese characters with an even number of backticks on the line → Chinese personal-name interpunct (卡尔·马克思), not converted;
    • Odd numbers of backticks both before and after the cursor → inside inline code, not converted;
    • Odd number of $ before the cursor → inside inline math, not converted;
    • https://... immediately before the cursor → inside a URL, not converted.

When the syntax tree is unavailable, the plugin automatically falls back to the heuristics — no configuration needed.

2. Backtick auto-pairing

When a character mapped to a backtick (·) is typed and conversion should happen:

  • No backtick after the cursor: insert a pair ``, placing the cursor between them (opening inline code);
  • A backtick already follows the cursor (e.g. the closing backtick produced by auto-pairing): delete the just-typed character and move the cursor past the existing backtick — this both "closes" the span and avoids duplicates like `code ``;
  • Odd number of backticks on the line (the opening backtick was typed in English mode, e.g. `code): insert a single closing backtick.

3. Undo merging

  • Realtime conversion: cm.dispatch({ changes, selection }) performs the replacement and the cursor move in a single CodeMirror transaction, undoable with one Ctrl+Z;
  • Batch conversion: the whole range is replaced with a single editor.replaceRange(), also producing a single undo record;
  • The isApplying guard flag prevents the plugin's own edits from triggering editor-change and causing infinite loops.

🛠 Development

npm install      # install dependencies
npm run dev      # watch mode build (main.js)
npm run build    # production build (tsc type check + esbuild)
npm test         # run the simulation test suite

Project structure

├── main.ts              # plugin core logic (including the settings tab)
├── manifest.json        # plugin manifest
├── styles.css           # settings panel styles
├── esbuild.config.mjs   # esbuild build configuration
├── tsconfig.json        # TypeScript configuration
├── package.json         # dependencies and scripts
├── versions.json        # version compatibility manifest
└── .github/workflows/release.yml   # release workflow with artifact attestations

📄 License

MIT

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.