强曰为道

与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

第 08 章:编辑器与工具集成

第 08 章:编辑器与工具集成

8.1 集成概览

Hunspell 被广泛集成在各种编辑器、办公套件和自动化工具中。本章详细讲解各平台的配置方法。

工具集成方式配置复杂度
LibreOffice内置引擎
Firefox / Thunderbird内置引擎
VS Code扩展★★
Emacsispell/flyspell★★★
Vim / Neovim插件★★
Sublime Text★★
CI/CD(GitHub Actions)命令行★★
pre-commit钩子★★
pandoc外部工具

8.2 LibreOffice

8.2.1 内置配置

LibreOffice 自带 Hunspell 引擎,配置通过菜单完成:

工具 → 语言 → 更多语言选项
  → 语言设置
    → 写作辅助
      → 可用语言模块 → Hunspell

8.2.2 安装额外词典

# 方法 1: 系统级安装(推荐)
sudo apt install hunspell-fr hunspell-de-de hunspell-es

# 方法 2: 通过 LibreOffice 扩展管理器
# 下载 .oxt 文件 → 工具 → 扩展管理器 → 添加

8.2.3 添加自定义词典

工具 → 语言 → 更多语言选项
  → 写作辅助
    → 自定义词典
      → 新建 → 输入词典名
      → 添加单词

自定义词典存储位置:

# Linux
~/.config/libreoffice/4/user/wordbook/

# 文件格式(.dic)
# 每行一个单词
Docker
Kubernetes
API
JSON

8.2.4 多语言文档

LibreOffice 支持在同一文档中混合使用多种语言的拼写检查:

  1. 选中段落
  2. 工具 → 语言 → 选中文本的语言
  3. 选择对应语言
# 也可以通过段落样式设置语言
# 格式 → 样式 → 编辑样式 → 字体 → 语言

8.2.5 排除单词

# 方法 1: 右键 → 全部接受
# 方法 2: 右键 → 添加到词典
# 方法 3: 编辑自定义词典文件

8.2.6 LibreOffice 词典路径

# 系统词典
/usr/share/hunspell/

# 用户词典
~/.config/libreoffice/4/user/wordbook/

# LibreOffice 扩展安装的词典
~/.config/libreoffice/4/user/uno_packages/cache/

8.3 Firefox / Thunderbird

8.3.1 内置拼写检查

Firefox 和 Thunderbird 内置 Hunspell 引擎,默认启用。

Firefox 设置:
  about:preferences → 常规 → 语言
    → 拼写检查 → 使用拼写检查
    → 选择词典语言

8.3.2 添加词典

Firefox → 右键文本框 → 语言 → 添加词典
  → 跳转到 Firefox 附加组件 → 语言工具
  → 安装所需语言的词典
# Firefox 词典扩展列表
# https://addons.mozilla.org/en-US/firefox/language-tools/

8.3.3 自定义词典管理

# Firefox 用户词典文件位置
~/.mozilla/firefox/<profile>/persdict.dat

# 文件格式:每行一个单词
Hunspell
API
JSON
# 管理自定义词典
Firefox → 设置 → 常规 → 语言 → 编辑词典
  → 添加/删除单词

8.3.4 Thunderbird 配置

Thunderbird → 编辑 → 首选项 → 编辑器
  → 拼写检查
    → 启用实时拼写检查
    → 选择词典语言

8.4 VS Code

8.4.1 安装拼写检查扩展

# 最流行的扩展:Code Spell Checker
# 扩展 ID: streetsidesoftware.code-spell-checker

# 通过命令面板安装
# Ctrl+Shift+P → Extensions: Install Extension → 搜索 "spell"

8.4.2 基本配置

// .vscode/settings.json
{
  // 语言设置
  "cSpell.language": "en",
  
  // 启用/禁用文件类型
  "cSpell.enableFileTypes": [
    "markdown",
    "plaintext",
    "latex",
    "restructuredtext"
  ],
  
  // 忽略的文件模式
  "cSpell.ignorePaths": [
    "node_modules",
    "package-lock.json",
    "*.min.js",
    "*.svg"
  ],
  
  // 最小单词长度
  "cSpell.minWordLength": 3,
  
  // 大小写敏感
  "cSpell.caseSensitive": true
}

8.4.3 自定义词典配置

// .vscode/settings.json
{
  "cSpell.customDictionaries": {
    // 工作区词典(推荐,可以提交到 Git)
    "workspace": {
      "name": "workspace",
      "path": "${workspaceFolder}/.vscode/dictionary.txt",
      "addWords": true,
      "scope": "workspace"
    },
    
    // 用户词典
    "user": {
      "name": "user",
      "path": "~/.cspell/user-words.txt",
      "addWords": true
    },
    
    // 项目特定词典
    "project": {
      "name": "project",
      "path": "${workspaceFolder}/.hunspell/project.dic",
      "addWords": true
    }
  }
}

8.4.4 项目词典文件

# .vscode/dictionary.txt
# 项目术语词典
TypeScript
JavaScript
Docker
Kubernetes
API
JSON
HTTP
GraphQL
gRPC
webhook
microservice
middleware
refactor
async
await
callback
closure
polymorphism

8.4.5 通过 cspell.json 配置

// cspell.json(放在项目根目录)
{
  "version": "0.2",
  "language": "en",
  "words": [
    "Docker",
    "Kubernetes",
    "TypeScript",
    "GraphQL",
    "gRPC",
    "webhook"
  ],
  "flagWords": [
    "teh",
    "adn",
    "hte"
  ],
  "ignoreWords": [],
  "patterns": [
    {
      "name": "markdown-code-block",
      "pattern": "/```[\\s\\S]*?```/g",
      "description": "Markdown 代码块"
    },
    {
      "name": "url",
      "pattern": "/(https?|ftp):[^\\s]+/gi",
      "description": "URL 链接"
    }
  ],
  "ignoreRegExpList": [
    "markdown-code-block",
    "url",
    "/`[^`]+`/g"
  ],
  "languageSettings": [
    {
      "languageId": "markdown",
      "dictionaries": ["en-US", "workspace"]
    },
    {
      "languageId": "latex",
      "dictionaries": ["en-US", "latex"]
    }
  ],
  "dictionaries": [
    "en-US",
    "companies",
    "softwareTerms"
  ],
  "import": [
    "@cspell/dict-en-us/cspell-ext.json",
    "@cspell/dict-software-terms/cspell-ext.json"
  ]
}

8.4.6 快捷操作

快捷键操作
Ctrl+.显示拼写错误快速修复
Ctrl+Shift+PcSpell打开拼写检查命令面板
右键 → Add to Dictionary添加到词典
右键 → Ignore Word忽略当前词

8.4.7 VS Code 任务集成

// .vscode/tasks.json
{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Spell Check",
      "type": "shell",
      "command": "hunspell",
      "args": [
        "-d", "en_US",
        "-p", ".hunspell/project.dic",
        "-l",
        "${workspaceFolder}/**/*.md"
      ],
      "group": "test",
      "presentation": {
        "reveal": "always",
        "panel": "new"
      },
      "problemMatcher": []
    }
  ]
}

8.5 Emacs

8.5.1 配置 flyspell

;; init.el — Emacs flyspell 配置

;; 启用 flyspell(实时拼写检查)
(setq ispell-program-name "hunspell")
(setq ispell-dictionary "en_US")

;; flyspell 在特定模式中启用
(add-hook 'text-mode-hook 'flyspell-mode)
(add-hook 'org-mode-hook 'flyspell-mode)
(add-hook 'markdown-mode-hook 'flyspell-mode)
(add-hook 'latex-mode-hook 'flyspell-mode)

;; 编程模式中只检查注释和字符串
(add-hook 'prog-mode-hook 'flyspell-prog-mode)

;; 自定义词典路径
(setq ispell-personal-dictionary "~/.hunspell_personal")

8.5.2 多语言配置

;; 多语言切换
(defun my-switch-hunspell-dict (lang)
  "切换 Hunspell 词典"
  (interactive
   (list (completing-read "语言: "
          '("en_US" "en_GB" "fr" "de_DE" "es" "zh_CN"))))
  (ispell-change-dictionary lang)
  (flyspell-mode 1)  ;; 重新启动 flyspell
  (message "切换到词典: %s" lang))

(global-set-key (kbd "C-c s l") 'my-switch-hunspell-dict)

;; 快速添加单词到个人词典
(defun my-add-word-to-dict ()
  "将光标下的单词添加到个人词典"
  (interactive)
  (let ((word (word-at-point)))
    (when word
      (ispell-send-string (concat "*" word "\n"))
      (message "已添加: %s" word))))

(global-set-key (kbd "C-c s a") 'my-add-word-to-dict)

8.5.3 flyspell 快捷键

快捷键操作
M-$修正光标处的拼写错误
C-M-i自动补全拼写建议
C-,跳到下一个拼写错误
C-.跳到上一个拼写错误

8.5.4 Hunspell + aspell 混合配置

;; 优先使用 hunspell,回退到 aspell
(cond
 ((executable-find "hunspell")
  (setq ispell-program-name "hunspell")
  (setq ispell-extra-args '("-d" "en_US")))
 ((executable-find "aspell")
  (setq ispell-program-name "aspell")
  (setq ispell-extra-args '("--sug-mode=ultra" "--lang=en_US"))))

8.6 Vim / Neovim

8.6.1 内置拼写检查

" 启用内置拼写检查(Vim 7+)
set spell
set spelllang=en_us

" 切换语言
set spelllang=fr

" 多语言
set spelllang=en_us,fr,de

" 拼写检查样式
highlight SpellBad cterm=underline gui=underline
highlight SpellCap cterm=underline gui=underline

8.6.2 拼写检查快捷键

快捷键操作
]s跳到下一个拼写错误
[s跳到上一个拼写错误
z=显示拼写建议列表
zg将单词加入好词词典
zw将单词标记为错误
zug撤销 zg
zuw撤销 zw

8.6.3 个人词典管理

" Vim 好词词典位置
" ~/.vim/spell/en.utf-8.add

" 使用自定义词典路径
set spellfile=.vim/spell/custom.utf-8.add

" 查看当前使用的词典
set spell?

8.6.4 vim-spellsuggest 插件

" 使用 fzf 提供更好的拼写建议界面
Plug 'junegunn/fzf.vim'

function! FzfSpellSuggest()
  let suggestions = spellsuggest(expand('<cword>'))
  call fzf#run({
    \ 'source': suggestions,
    \ 'sink': function('FzfSpellReplace'),
    \ 'options': '+m',
    \ 'down': '30%'
    \ })
endfunction

function! FzfSpellReplace(word)
  exe 'normal! ciw'.a:word
endfunction

nnoremap z= :call FzfSpellSuggest()<CR>

8.6.5 Neovim 集成 (nvim-spell)

-- init.lua — Neovim 拼写检查配置
vim.opt.spell = true
vim.opt.spelllang = "en_us"

-- 自定义词典
vim.opt.spellfile = vim.fn.stdpath("config") .. "/spell/custom.utf-8.add"

-- 快速添加单词的快捷键
vim.keymap.set('n', '<leader>sa', 'zg', { desc = "添加到词典" })
vim.keymap.set('n', '<leader>su', 'zug', { desc = "撤销添加" })
vim.keymap.set('n', '<leader>s=', 'z=', { desc = "显示建议" })

8.7 Sublime Text

8.7.1 安装词典包

Ctrl+Shift+P → Package Control: Install Package
  → 搜索 "Dictionaries" 或 "Spell Check"

8.7.2 配置

// Preferences → Settings
{
  // 启用拼写检查
  "spell_check": true,
  
  // 词典路径(默认使用系统词典)
  "dictionary": "Packages/Language - English/en_US.dic",
  
  // 拼写检查触发间隔(毫秒)
  "dictionary_close_on_save": false
}

8.7.3 快捷键

快捷键操作
F6切换拼写检查
Ctrl+Shift+;跳到下一个错误
Ctrl+Shift+,拼写建议

8.8 CI/CD 集成

8.8.1 GitHub Actions

# .github/workflows/spellcheck.yml
name: Spell Check

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

jobs:
  spellcheck:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Install Hunspell
        run: |
          sudo apt-get update
          sudo apt-get install -y hunspell hunspell-en-us
      
      - name: Run spell check
        run: |
          # 检查所有 Markdown 文件
          ERRORS=""
          while IFS= read -r -d '' file; do
            file_errors=$(hunspell -l -d en_US -p .hunspell/project.dic "$file" 2>/dev/null | sort -u)
            if [ -n "$file_errors" ]; then
              ERRORS="$ERRORS\n$file:\n$file_errors"
            fi
          done < <(find . -name "*.md" -not -path "./.git/*" -print0)
          
          if [ -n "$ERRORS" ]; then
            echo "::error::发现拼写错误"
            echo -e "$ERRORS"
            exit 1
          fi
          echo "✓ 拼写检查通过"
      
      - name: Generate spell report
        if: failure()
        run: |
          echo "## 拼写检查报告" > spell_report.md
          echo "" >> spell_report.md
          while IFS= read -r -d '' file; do
            errors=$(hunspell -l -d en_US -p .hunspell/project.dic "$file" 2>/dev/null | sort -u)
            if [ -n "$errors" ]; then
              echo "### $file" >> spell_report.md
              echo '```' >> spell_report.md
              echo "$errors" >> spell_report.md
              echo '```' >> spell_report.md
            fi
          done < <(find . -name "*.md" -not -path "./.git/*" -print0)
          
          cat spell_report.md

8.8.2 GitLab CI

# .gitlab-ci.yml
stages:
  - lint

spellcheck:
  stage: lint
  image: ubuntu:22.04
  before_script:
    - apt-get update
    - apt-get install -y hunspell hunspell-en-us
  script:
    - |
      ERRORS=$(find docs/ -name "*.md" -exec cat {} \; | \
        hunspell -d en_US -p .hunspell/project.dic -l | sort -u)
      if [ -n "$ERRORS" ]; then
        echo "拼写错误:"
        echo "$ERRORS"
        exit 1
      fi
  artifacts:
    when: on_failure
    paths:
      - spell_report.txt

8.8.3 pre-commit 框架集成

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: hunspell-check
        name: Hunspell Spell Check
        entry: hunspell -l -d en_US -p .hunspell/project.dic
        language: system
        files: '\.(md|txt|rst)$'
        pass_filenames: true
        require_serial: false
# 安装 pre-commit
pip install pre-commit

# 安装钩子
pre-commit install

# 手动运行
pre-commit run hunspell-check --all-files

8.8.4 自定义 CI 脚本

#!/bin/bash
# ci-spellcheck.sh — CI 拼写检查脚本
set -euo pipefail

DICT="${DICT:-en_US}"
PERSONAL_DICT="${PERSONAL_DICT:-.hunspell/project.dic}"
FILE_PATTERN="${FILE_PATTERN:-*.md}"
EXIT_CODE=0
REPORT=""

echo "=== CI 拼写检查 ==="
echo "词典: $DICT"
echo "个人词典: $PERSONAL_DICT"
echo "文件模式: $FILE_PATTERN"
echo ""

# 收集所有错误
while IFS= read -r -d '' file; do
    errors=$(hunspell -l -d "$DICT" -p "$PERSONAL_DICT" "$file" 2>/dev/null | sort -u)
    if [ -n "$errors" ]; then
        error_count=$(echo "$errors" | wc -l)
        echo "✗ $file ($error_count 个错误)"
        REPORT="$REPORT\n## $file\n\`\`\`\n$errors\n\`\`\`\n"
        EXIT_CODE=1
    else
        echo "✓ $file"
    fi
done < <(find . -type f -name "$FILE_PATTERN" -not -path "./.git/*" -print0)

echo ""

# 生成报告
if [ "$EXIT_CODE" -ne 0 ]; then
    echo "=== 拼写错误报告 ==="
    echo -e "$REPORT"
    
    # 在 GitHub Actions 中创建注释
    if [ -n "${GITHUB_STEP_SUMMARY:-}" ]; then
        echo "## 🔤 拼写检查报告" >> "$GITHUB_STEP_SUMMARY"
        echo -e "$REPORT" >> "$GITHUB_STEP_SUMMARY"
    fi
fi

exit $EXIT_CODE

8.9 Pandoc 集成

8.9.1 Pandoc 拼写检查

# Pandoc 可以配合 hunspell 进行拼写检查
# 将文档转为纯文本后检查

# Markdown → 纯文本 → hunspell
pandoc -t plain input.md | hunspell -d en_US -l

# 只检查 Markdown 中的文本内容(忽略标记)
pandoc -t markdown --wrap=none input.md | \
    sed 's/\[.*\](.*)//g' |  # 移除链接
    sed 's/\*\*//g' |         # 移除粗体
    sed 's/\*//g' |           # 移除斜体
    hunspell -d en_US -l

8.9.2 Pandoc 过滤器

#!/usr/bin/env python3
"""pandoc_spellcheck.py — Pandoc 拼写检查过滤器"""
import panflute as pf
import subprocess

def spellcheck(elem, doc):
    """检查文本元素的拼写"""
    if isinstance(elem, pf.Str) and len(elem.text) >= 3:
        # 只检查纯文本(非代码、非链接)
        if not any(isinstance(parent, (pf.Code, pf.CodeBlock, pf.Link))
                    for parent in [elem.parent]):
            result = subprocess.run(
                ["hunspell", "-d", "en_US", "-l"],
                input=elem.text, capture_output=True, text=True
            )
            if result.stdout.strip():
                pf.debug(f"拼写错误: {elem.text} (在 {elem.parent})")
                elem.text = f"⚠{elem.text}⚠"
    return elem

if __name__ == "__main__":
    pf.run_filter(spellcheck)
# 使用过滤器
pandoc -F pandoc_spellcheck.py input.md -o output.html

8.10 容器化集成

8.10.1 Docker 拼写检查镜像

# Dockerfile
FROM ubuntu:22.04

RUN apt-get update && \
    apt-get install -y --no-install-recommends \
    hunspell \
    hunspell-en-us \
    hunspell-fr \
    hunspell-de-de \
    && rm -rf /var/lib/apt/lists/*

COPY .hunspell/project.dic /opt/dictionaries/
COPY .hunspell/project.aff /opt/dictionaries/

WORKDIR /docs

ENTRYPOINT ["hunspell"]
CMD ["-d", "en_US", "-p", "/opt/dictionaries/project.dic", "-l"]
# 构建
docker build -t spellcheck .

# 使用
docker run --rm -v $(pwd):/docs spellcheck
docker run --rm -v $(pwd):/docs spellcheck -d fr -l

8.10.2 Docker Compose 配置

# docker-compose.yml
version: '3.8'
services:
  spellcheck:
    build: .
    volumes:
      - .:/docs
      - ./.hunspell:/opt/dictionaries
    command: >
      hunspell -d en_US
      -p /opt/dictionaries/project.dic
      -l *.md

8.11 各平台词典路径速查

平台词典路径
Ubuntu/Debian/usr/share/hunspell/
Fedora/usr/share/hunspell/
Arch Linux/usr/share/hunspell/
macOS (Homebrew)/usr/local/share/hunspell//opt/homebrew/share/hunspell/
Windows (MSYS2)C:\msys64\mingw64\share\hunspell\
LibreOffice 用户~/.config/libreoffice/4/user/wordbook/
Firefox 用户~/.mozilla/firefox/<profile>/persdict.dat
VS Code~/.cspell/ 或项目 .vscode/dictionary.txt
Emacs~/.hunspell_personal 或自定义路径

8.12 本章小结

工具推荐扩展/配置自定义词典方式
LibreOffice内置扩展管理器 + 用户词典
Firefox内置about:preferences → 语言
VS CodeCode Spell CheckercSpell.json + .vscode/settings.json
Emacsflyspellispell-personal-dictionary
Vim/Neovim内置 :set spellspellfile
Sublime TextDictionaries 包用户设置
CI/CDhunspell CLI项目词典 + pre-commit

扩展阅读