textlintとFlycheckによるEmacs上でのテキスト校正
この記事はEmacs Advent Calendar 2021の13日目の記事です。
こんにちは。
突然ですが、Emacsでは、人工言語(Python, Rust等)でのコーディングだけでなく、メモ、ブログ、原稿書き等の自然言語(日本語や英語等)での入力も多数発生します。 自分用のメモだけであれば自分が理解できれば良いですが、他の人にも読んでもらうならば冗長な表現や誤字・脱字をなるべく避けたいものです。
そこで今回は、textlintとEmacsのFlycheckを用いて、リアルタイムのテキスト校正方法を紹介します。 この記事が少しでも読まれた方の参考になると嬉しいです。
textlint
textlintとは、テキストファイルを特定 のルールに従ってチェックや修正してくれるツールです。@azu_reさんという方が作られています。 ルールには色々あり、技術文書向け、誤字・脱字、英語向け、日本語向けのルール等、多数公開されています。
まず、このツールを用いて、テキスト校正をできるようにします。
textlintのインストール
textlintのインストールにはnodejsが必要になりますので、nodejsをインストールしておきます。 nodejsのインストール方法は色々な記事がありますので、そちらを参照いただければと思います。 私もM1 Macでのnodejsのインストール記事を書いていますので、よろしければ参考にしてください。
nodejsがインストールされていれば、以下コマンドでtextlintをインストールします。
npm install -g textlint
公式のインストールではlocalでのインストールを推奨していますが、私は色々な箇所で利用するためglobalにインストールしています。
テキスト校正ルールのインストール
textlintのみではテキスト校正ができませんので、利用したいテキスト校正ルールをインストールします。 テキスト校正ルールは色々な種類が公開されていますので、自分が使いたいルールを選びます。
参考までに私が使っているルールを以下に記載します。
言語 | ルール名 | 概要 |
---|---|---|
日本語 | textlint-rule-preset-ja-technical-writing | 技術文書向けのルール |
日本語 | textlint-rule-preset-ja-spacing | スペースに関するルール |
英語 | textlint-rule-write-good | write-goodに基づくルール |
英語 | textlint-rule-en-capitalization | 大文字小文字に関するルール |
英語 | textlint-rule-alex | ALEXに基づくルール |
英語 | textlint-rule-common-misspellings | Wikipediaに基づくスペルミスのルール |
ルールも以下のようにnpmでglobalインストールします。
npm install -g textlint-rule-preset-ja-technical-writing
org-modeへの対応
Emacsにはorg-modeがあります。 org-modeでのフォーマット(.orgファイル)でもtextlintを使いたいので、以下コマンドでorg-mode用のpluginをインストールします。
npm install -g textlint-plugin-org
なお、textlint-plugin-orgの依存関係になっているdate-fnsのバージョンが3以上だとエラーになるので、textlint-plugin-orgのインストール後にdate-fnsのバージョン2.30.0にしています。
言語によるルール選択とプラグイン設定
textlintのルールやプラグインは、コマンドの引数で指定するか、Configファイルを指定して、適用します。
日本語/英語で適用したいルールが異なりますので、日本語用と英語用のConfigファイルを作成します。 保存ディレクトリ は各自で自由に設定してださい(私は~/.config/textlintにしています)。
- 日本語用Configファイル
~/.config/textlint/textlintrc_ja.json
{ "rules": { "preset-ja-technical-writing": { "max-kanji-continuous-len": { "max": 10 } }, "preset-ja-spacing": { "ja-nakaguro-or-halfwidth-space-between-katakana": true, "ja-no-space-around-parentheses": true, "ja-no-space-between-full-width": true, "ja-space-between-half-and-full-width": { "space": ["alphabets"] }, "ja-space-after-exclamation": false, "ja-space-after-question": false, "ja-space-around-code": false, "ja-space-around-link": false } } }
- 英語用Configファイル
~/.config/textlint/textlintrc_en.json
{ "rules": { "alex": true, "common-misspellings": true, "write-good": true, "en-capitalization": true } }
次に、自動で以下の2点を実現する必要がありますので、私は以下のshellscript(textlint.sh)を作成しています。
- 言語別に適用するConfigファイルを選択
- text内にひらがなが含まれていれば日本語、含まれていなければ英語と判定
- orgファイルにはorg用オプションを指定
- 拡張子がorgであれば、org用オプションを追加
なお、このtextlint.shはEmacsから呼び出しますので、EmacsからPathが通っている箇所に保存してください。私は~/local/bin/textlint.shとして保存しています。
#!/usr/bin/env bash
set -eu
set -o pipefail
FILENAME="$1"
EXTENSION="${FILENAME##*.}"
determine_textlintrc() {
if grep -q "[ぁ-ん]" "$1"; then
echo "${HOME}/.config/textlint/textlintrc/textlintrc_ja.json"
else
echo "${HOME}/.config/textlint/textlintrc/textlintrc_en.json"
fi
}
TEXTLINTRC=$(determine_textlintrc "$FILENAME")
ARGS=(--format unix --config "$TEXTLINTRC" "$FILENAME")
if [ "$EXTENSION" = "org" ]; then
ARGS+=(--plugin org)
fi
textlint "${ARGS[@]}"
最後に、textlint.shに実行権限を付与します。
chmod +x ~/.local/bin/textlint.sh
textlint.shの動作確認
では、実際に動作確認をしてみます。まず、test用のファイルを作成します。
今日は、天気が良さそうに思います。
i talk abotu English.
上記で作成したtest用ファイルを引数にしてtextlint.shを実行すると、ちゃんと言語ごとに警告が表示されていることが確認できます。 ここには結果を記載していませんが、orgファイルでも適切に利用できます。
% textlint.sh test_ja.txt
test_ja.txt:1:13: 弱い表現: "思います" が使われています。 [Error/ja-technical-writing/ja-no-weak-phrase]
% textlint.sh test_en.txt
test_en.txt:1:1: Paragraph: Follow the standard capitalization rules for American English.
See https://owl.english.purdue.edu/owl/resource/592/01/ [Error/en-capitalization]
test_en.txt:1:8: This is a commonly misspelled word. Correct it to about [Error/common-misspellings]
以上で、textlintの設定が完了です。
Flycheck
次にEmacsでのリアルタイム実行です。 Emacsでは、構文チェッカーであるFlycheckを用いてリアルタイムのtextlintを実現します。
Flycheckのインストールと初期設定
まず、Flycheckパッケージをインストールします。 Flycheckのインストール方法は色々な記事がありますので、そちらを参照いただければと思います。 私もFlycheckのインストールと初期設定記事を書いていますので、よろしければ参考にしてください。
;; flycheckのインストールと初期設定
(leaf flycheck
:ensure t
:hook ((text-mode-hook markdown-mode-hook gfm-mode-hook org-mode-hook) . flycheck-mode)
:custom ((flycheck-display-errors-delay . 0.3)
(flycheck-indication-mode . 'left-margin))
:config
(add-hook 'flycheck-mode-hook #'flycheck-set-indication-mode)
(leaf flycheck-inline
:ensure t
:hook (flycheck-mode-hook . flycheck-inline-mode))
)
私はPackage管理のパッケージとしてleaf.elを使用しており、leaf.elの記法で設定しています。
Flycheckの設定
Flycheckでtextlintを使うためには、textlint向けのチェッカーを作成する必要があります。 こちらを参考に以下のようにチェッカーを作成しました。
;; textlint用のチェッカー
(flycheck-define-checker textlint
"A linter for text."
:command ("textlint.sh" source)
:error-patterns
((warning line-start (file-name) ":" line ":" column ": "
(id (one-or-more (not (any " "))))
(message (one-or-more not-newline)
(zero-or-more "\n" (any " ") (one-or-more not-newline)))
line-end))
:modes (text-mode markdown-mode gfm-mode org-mode))
上記では、textlint用チェッカーをtextとmarkdown、orgファイルで起動するようにしています。
また、:command
で先ほど作成したtextlint.shを指定しています。
私はtextlint.shをEmacsからpathが通っている箇所に保存しているので、ファイル名を直接指定します。
pathを通していない場合は、pathを通すかtextlint.shを絶対pathで指定してみてください。
動作確認
ではEmacsで動作確認をします。 ちょうど本記事もEmacsで書いていますので、その画面を以下に示します。
しっかり、適切でない表現が指摘されていることが分かります。これで完了です。
終わりに
ここまで、読んでいただき、ありがとうございます。 これでリアルタイムでのテキスト校正環境ができあがりました。
もちろん、指摘だけでなく自動修正も可能ですが、どのように修正されるか分かりませんし、指摘による気付きで自身の執筆能力が向上するはずです(たぶん)。
この記事で少しでもEmacsユーザが増え、Emacs界?の盛り上がりに貢献できると嬉しいです。
すべてのEmacsユーザに幸あれ!