search
LoginSignup
34
Help us understand the problem. What are the problem?

posted at

updated at

PrettierでMarkdownをフォーマットしたときの英語と日本語の間に入るスペースをどうにかする

はじめに

Prettier - Code formatter(VSCode拡張)でMarkdownをフォーマットすると、英語(アルファベット)と日本語の間に半角スペースが入ります。

例えば、
IPアドレスは間にスペースが入りIP アドレスとなります。

この問題は以下の記事でも指摘されています。
VSCodeでMarkdownの自動フォーマット&整形ルールを自由に設定

この原因を調査し、強引に修正しました。

コメントより追記(2021.04.05)

この問題に対処する便利なプラグインが @tats-u さんにより作成されました。
記事の『prettier-plugin-md-nocjspを利用する』の項だけお読み下さい。

prettier-plugin-md-nocjspを利用する

環境

動作を確認した環境は以下の通りです。

  • Windows 10 Pro(64bit)
  • VS Code 1.64.2
  • Prettier - Code formatter 9.2.0

原因

原因はPrettierにあります。
これはPrettierのPlaygroundでも動作がそのようになることから明らかです。

対処法がないかググってみると、以下のissueが見つかりました。
Markdown: unnecessary space is inserted between Korean & English words
韓国語と英語の間にスペースが入ってしまうというissueです。
issueを読むと以下のことが分かります。

  • CJKV日中韓越情報処理によれば、慣例として余分なスペースを使用するとある。
  • 過去に議論があったようで(ref: ikatyang/cjk-regex#48)そちらを読むと、W3C typographyの要件にもスペースを入れるとある。
  • PrettierのMarkdown対応部分を書いてる人は台湾に住んでいる美少女らしい。

スペース無し派、劣勢ですかね・・・
でもこれテキストではなく、プレビューしたときにCSSでスタイリングすべきことのような気がします。

そして、issueを受けて韓国語はスペースを入れないという仕様に変更されています。
どのような修正がされたのかは、下記を見ると大体わかります。
https://github.com/prettier/prettier/pull/5040/commits/da6186995df3ba1f8bdeb126d794fb32c404bcdb

ここまで分かれば何とか出来そうですね。

対処

対処方法として2パターン思いつきました。

  • 例外としている韓国語のパターンに日本語も追加する
  • スペースを追加している処理をなくす

VSCodeの拡張はJavaScriptで書かれているので、直接拡張のjsファイルを修正して対処できます。

対処法1

まず、Prettierのファイルがあるディレクトリを開きます。
Windowsであれば、下記をコピペしてファイル名を指定して実行で開けます。
%USERPROFILE%\.vscode\extensions\esbenp.prettier-vscode-3.20.0\node_modules\prettier

ディレクトリ内のindex.jsをコピーしてindex.js.bkなどとしてバックアップしておきます。

index.jsをエディタで開き、38438行目まで移動します。
38438 から 38441行目が以下のようになっています。

index.js
var cjkPattern = json.cjkPattern,
    kPattern = json.kPattern,
    punctuationPattern = json.punctuationPattern;
var getLast$3 = util.getLast;

ここのkPatternと言う変数が韓国語の判定に使われているので、38439行目を修正し以下のようにします。

index.js
var cjkPattern = json.cjkPattern,
    kPattern = json.cjkPattern,
    punctuationPattern = json.punctuationPattern;
var getLast$3 = util.getLast;

kPatternにcjkPatternと同じ、json.cjkPatternを代入します。
中国語も巻き添えですが、まぁ良しとします。

対処法2

対処法1を行った場合は不要です。

まず、Prettierのファイルがあるディレクトリを開きます。

Windowsであれば、下記をコピペしてファイル名を指定して実行で開けます。
%USERPROFILE%\.vscode\extensions\esbenp.prettier-vscode-3.20.0\node_modules\prettier

ディレクトリ内のindex.jsをコピーしてindex.js.bkなどとしてバックアップしておきます。

index.jsをエディタで開き、38514行目まで移動します。
38514 から 38529行が以下のようになっています。

index.js
if (lastNode && lastNode.type === "word") {
      if (lastNode.kind === KIND_NON_CJK && node.kind === KIND_CJ_LETTER && !lastNode.hasTrailingPunctuation || lastNode.kind === KIND_CJ_LETTER && node.kind === KIND_NON_CJK && !node.hasLeadingPunctuation) {
        nodes.push({
          type: "whitespace",
          value: " "
        });
      } else if (!isBetween(KIND_NON_CJK, KIND_CJK_PUNCTUATION) && // disallow leading/trailing full-width whitespace
      ![lastNode.value, node.value].some(function (value) {
        return /\u3000/.test(value);
      })) {
        nodes.push({
          type: "whitespace",
          value: ""
        });
      }
    }

38518行目

value: " "

となっているのを

value: ""

とします。
もちろん中国語も巻き添えです。

textlintで対処する方法

根本的な解決ではありませんが、textlintで対処するのも良いです。

textlintについては、以下の記事に情報がまとまってます。
Qiitaやはてブロに投稿するようなユーザーはみんなtextlintを使うと捗るぞ!

私はtextlintのpreset-ja-spacingを有効にして、半角文字と全角文字の間にスペースを入れたら警告を出すようにしています。

prettier-plugin-md-nocjspを利用する

作者の@tats-uさんよりコメントで紹介頂いた、prettier-plugin-md-nocjsp を利用する方法です。
もっとも手軽でスマートなので、こちらを利用することを推奨します。

プラグインの詳細については以下の作者様の記事を一読頂ければと思います。
和欧文字間(漢字仮名と英数字の間)に半角スペースが挿入されないようにするPrettier Markdownプラグインを作った

導入方法についてはプラグインのgithubに丁寧に書かれています。
https://github.com/tats-u/prettier-plugin-md-nocjsp#readme

注意点として
PrettierのVSCode拡張機能にバンドルされているPrettierではPrettierプラグインが利用できません。
Prettierを別途グローバル or ローカルにインストールする必要があります。

推奨はローカルインストールです。

ローカルインストール(推奨)の場合

カレントディレクトリをプロジェクトルートに移動します
以下をコマンド実行し、prettier-plugin-md-nocjsp をインストールします。

npm install --save-dev prettier-plugin-md-nocjsp
npm install prettier -D --save-exact

次に .prettierrcをプロジェクトルートに追加します。

.prettierrc
# *snip*
overrides:
  - files:
      - "*.md"
      - README
    options:
      parser: markdown-nocjsp
  - files:
      - "*.mdx"
    options:
      parser: mdx-nocjsp

グローバルインストールの場合

以下をコマンド実行し、prettier-plugin-md-nocjsp をインストールします。

npm install -g prettier-plugin-md-nocjsp
npm install -g prettier

さらにprettier拡張の設定で prettier.resolveGlobalModulestrue にします。
prettier.resolveGlobalModulestrue だと動かなくなりました(2022.02.13)
true になっている場合 false にしてください。

次に .prettierrcをユーザーディレクトリ(C:\Users\ユーザー名)に追加します。

.prettierrc
# *snip*
overrides:
  - files:
      - "*.md"
      - README
    options:
      parser: markdown-nocjsp
      plugins:
        - "./AppData/Roaming/npm/node_modules/prettier-plugin-md-nocjsp"
  - files:
      - "*.mdx"
    options:
      parser: mdx-nocjsp
      plugins:
        - "./AppData/Roaming/npm/node_modules/prettier-plugin-md-nocjsp"

こちらは @u3xbf8i9 さんのコメントが参考になりました。ありがとうございます。

注意

Prettier - Code formatter、Prettierのバージョンアップでこの内容が通用しなくなることがあります。
ご了承ください。

最後に

無理やり修正していますが、プルリクやissueを上げた方が建設的だと思います。
でも、英語無理!

追記(2019.03.08)

issueにあがってました、ありがたい。
https://github.com/prettier/prettier/issues/5938

さらに追記(2020.02.14)

https://github.com/prettier/prettier/issues/6385

オプションで切り替える案が出されてました。

日本語と中国語が切り離せない。
中国語ではスペースを入れるのが一般的派と、中国語でも入れないよ派など
意見が割れているようです。
Prettier自体にあまりオプションを入れたくないともあります。
解決はすぐには難しそうですね。

参考

https://github.com/ikatyang/cjk-regex/issues/48
https://github.com/prettier/prettier/issues/5028
https://github.com/prettier/prettier/pull/5040/commits/da6186995df3ba1f8bdeb126d794fb32c404bcdb
https://qiita.com/kumapo0313/items/92d1597da5f3752f6584#comment-e328de87992dbb82c9a1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
34
Help us understand the problem. What are the problem?