LaTeX Workshop のインテリセンスをカスタマイズする

<!-- # LaTeX Workshop のインテリセンスをカスタマイズする -->

:::note info
[LaTeX Workshop \| James Yu](https://marketplace.visualstudio.com/items?itemName=James-Yu.latex-workshop)
投稿時; ver.8.23.0 (2022/3 現在)、最終更新時; **ver.10.4.1**
:::

<!--
:::note warn
2022/12/13 現在 (ver.9.1.1)、次の更新で [\# インテリセンスデータ](#-インテリセンスデータ) 節や [\# 新しいインテリセンスデータを作成する](#-新しいインテリセンスデータを作成する) 節でのインテリセンスデータの構成が非互換的に更新される可能性があります。

> [New `cwl` parsing function and data format by James-Yu · Pull Request #3576 · James-Yu/LaTeX-Workshop](https://github.com/James-Yu/LaTeX-Workshop/pull/3576)

本記事は次の更新に対応して編集追記する可能性はありますが、編集追記するモチベーションがあるか分かりません。上に示した Pull Request と更新されたインテリセンスデータを確認すれば、どのように変更されたか理解できると思います。

LaTeX Workshop の更新によってインテリセンスデータの構成が変更された場合には、十分に注意してください。
:::
-->

<!-- :::note warn
2023/01/09 現在、最新の **ver.9.4** でインテリセンスデータのフォーマットに非互換的な変更が加えられています。

最新のインテリセンスデータのフォーマットを知りたい場合は、以下の README を確認してください。

[LaTeX-Workshop/dev/README.md at master · James-Yu/LaTeX-Workshop](https://github.com/James-Yu/LaTeX-Workshop/blob/master/dev/README.md#ctanpkglist.py)
::: -->

LaTeX Workshop では数多くのコマンドや環境がインテリセンスとして提供されています。また、ユーザーはスニペットを作成することで簡単に打つことが出来るようになります。

しかしながら、「スニペットで作成したコマンド」と「インテリセンスから提供されるコマンド」は少しだけサジェストの雰囲気が異なります。また、独自パッケージを利用している場合や、LaTeX Workshop で提供していないインテリセンスを利用したい場合には対応できません。

今回は、デフォルトのスニペットの変更やスニペットではなく新しいインテリセンスとして読み込ませる方法を考えたい。

:::note alert
これらの変更後は VSCode を再起動する必要があります。
:::

本記事では、新しいインテリセンスデータの JSON ファイルを手で作成する方法を紹介していますが、拡張機能の開発側では Python によって CWL ファイルから生成されています。
これに関して、具体例として以下のような記事が公開されました。

https://qiita.com/take_me/items/c3cd95492ff88a7e43ee

本記事が拡張機能のバージョンによって対応しきれていなかったり、まとめてインテリセンスデータの JSON ファイルを生成したい場合は、この記事を参照してください。

## スニペットとインテリセンス

LaTeX Workshop では多くのインテリセンスが提供されています。インテリセンスは `\` に続けてコマンドを打つとサジェストとして表示されます。
しかしながら、VSCode のスニペットとして prefix が `\` から始まるものを登録していると、表示が少し奇妙な印象を受けます。

例えば、`\chaplin` というコマンドをスニペットとして登録しているとします。`\chapter` を打とうとして `\chap` まで打つと次のようになります。

![chaplin](https://i.gyazo.com/1798bcab5bad78d5cd5f2a0afbaa662b.png)

サジェスト左側の記号が Snippet prefixes と Methods and Functions で異なっています。ちょっと具合の悪い感じがします。また、`\` を押下した時点でこれらの prefix が `\` から始まるスニペットがサジェストされてしまいます。
これらは出来るだけ避けたいです。

## ○ インテリセンスに関する基本的な設定

基本的なインテリセンスやサジェストの設定は次のようになっているものとします。

```json
{
  "[latex]": {
    "editor.quickSuggestions": {
      "other": true,
      "comments": false,
      "strings": false
    },
    "editor.suggest.snippetsPreventQuickSuggestions": false,
  },
  "latex-workshop.intellisense.package.enabled": true,
  "latex-workshop.intellisense.argumentHint.enabled": true,
}
```

### ■ インテリセンス更新のタイミング

インテリセンスはパッケージから提供されるコマンドや環境、label 名などを表示させることが出来るが、これらを読み込むタイミングは保存したときとなっています。（デフォルト）

これを編集中に常に解析・更新させることも出来る。以下の設定を `true` に変更すれば良いです。また、解析の間隔は `1000` ミリ秒となっています。

```json
  "latex-workshop.intellisense.update.aggressive.enabled": false,
  "latex-workshop.intellisense.update.delay": 1000,
```

ただし、当然ながら処理が重くなってしまうので、処理速度に自信のある PC 以外は有効にしないことをおすすめしておきます。

## ○ インテリセンスデータ

インテリセンスデータはリポジトリの次のディレクトリを確認すれば良いです。

> [LaTeX-Workshop/data at master · James-Yu/LaTeX-Workshop](https://github.com/James-Yu/LaTeX-Workshop/tree/master/data)

ここの README を確認すると、以下の 2 つのファイルと 2 種類のファイルによってインテリセンスデータが構成されています。

- デフォルトのインテリセンスデータ
    - <samp>commands.json</samp> <sup>[[↗]](https://github.com/James-Yu/LaTeX-Workshop/blob/master/data/commands.json)</sup>
    - <samp>environments.json</samp> <sup>[[↗]](https://github.com/James-Yu/LaTeX-Workshop/blob/master/data/environments.json)</sup>
- パッケージや文書クラスごとのインテリセンスデータ（`data/packages/` <sup>[[↗]](https://github.com/James-Yu/LaTeX-Workshop/tree/master/data/packages)</sup> 以下に含まれている）
    - <samp>*.json</samp>
    - <samp>class-*.json</samp>

<samp>*.json</samp> の `*` はパッケージ名に、`class-` は文書クラスに対応しています。

<!-- パッケージやクラスごとのインテリセンスデータは、Sublime Text の [LaTeXing による cwl ファイル](https://github.com/LaTeXing/LaTeX-cwl) を `pkgcommand.py` <sup>[[↗]](https://github.com/James-Yu/LaTeX-Workshop/blob/master/dev/pkgcommand.py)</sup> を使って変換することで自動的に作成するようですが、今回は手動で作成することを考えます。自作コマンドや自作環境程度であれば適当に作成することが出来るでしょう。 -->

<!-- :::note info
Ver.9.2 以降、コマンドに関するファイル `*_cmd.json` と環境に関するファイル `*_env.json` の区別はなくなり、統合された `*.json` のみとなる。（`*` はパッケージ名）
::: -->

### ■ インテリセンスデータの読み込み順序

LaTeX Workshop では上で示したデータを次の順序で読み込みます。また、`\newcommand` などで新たに定義したコマンドや環境を自動的に解析してインテリセンスデータとして読み込むことが出来ます。

1. <samp>commands.json</samp> と <samp>environments.json</samp> が読み込まれる
2. `\usepackage` したパッケージから提供されるコマンドを自動補完する
    - 主要パッケージのみがサポートされている
3. 開かれているファイル内の `\newcommand` などで定義されているコマンド
    - `\input` されているファイル内の `\newcommand` などで定義されているコマンド
    - インテリセンスの読み込みは変更されたファイルの保存時に実行される（デフォルト）

使用感として、`\newcommand` などを解析したインテリセンスは括弧の数が安定しないように感じます。また、xparse によるオプション引数のための括弧にも強くない印象があります。
出来れば、<samp>*.json</samp> を作成して読み込ませたい。

## ○ 既存のインテリセンスを変更する

<samp>commands.json</samp> であるデフォルトのインテリセンスデータを上書きできます。これには 300 種類程度のインテリセンスが集録されています。ただし、これによって可能な設定は削除を含む上書きのみであり、新たなインテリセンスを追加することは出来ません。

```json
  "latex-workshop.intellisense.commandsJSON.replace": {},
```

ここでは、<samp>commands.json</samp> のスニペットを変更するため、設定されている `object_name` を知る必要があります。（<samp>commands.json</samp> 内では `object_name` がスニペットの呼び出しとなっている）

<details>
<summary><samp>commands.json</samp> のコマンドスニペットの例（折りたたみ）</summary>
<div>

<samp>commands.json</samp> の [`\label{}` の例](https://github.com/James-Yu/LaTeX-Workshop/blob/master/data/commands.json#L240-L243) を見てみましょう。

このとき、以下を見て明らかなように `label{}` が `object_name` に対応しています。

```json
  "label{}": {
    "command": "label{...}",
    "snippet": "label{${1}}"
  },
```

`~.commandsJSON.replace` では、この `snippet` を変更できます。

</div>
</details>

### ■ 例 1

数式中で利用する括弧は高さを調整できます。デフォルトでは `\left(` とすると 1 行に `\left(\right)` が出てきます。

コードを確認する際には、改行された以下のような状態の方が見やすい場合があるため、複数行に渡って出るように変更してみましょう。

```latex
\begin{equation}
    a
    % ↓ このように複数行で出したい
    \left(
      x + \frac{b}{2a}
    \right)^2
    - \frac{b^2}{4a} + c
\end{equation}
```

正規表現で改行とタブを挿入しました。

```json
  "latex-workshop.intellisense.commandsJSON.replace": {
    "left(": "left(\n\t${1:$TM_SELECTED_TEXT}\n\\right)",
    "bigl(": "bigl(\n\t${1:$TM_SELECTED_TEXT}\n\\bigr)",
    "Bigl(": "Bigl(\n\t${1:$TM_SELECTED_TEXT}\n\\Bigl)",
    "biggl(": "biggl(\n\t${1:$TM_SELECTED_TEXT}\n\\biggr)",
    "Biggl(": "Biggl(\n\t${1:$TM_SELECTED_TEXT}\n\\Biggr)",
    "left[": "left[\n\t${1:$TM_SELECTED_TEXT}\n\\right]",
    "bigl[": "bigl[\n\t${1:$TM_SELECTED_TEXT}\n\\bigr]",
    "Bigl[": "Bigl[\n\t${1:$TM_SELECTED_TEXT}\n\\Bigl]",
    "biggl[": "biggl[\n\t${1:$TM_SELECTED_TEXT}\n\\biggr]",
    "Biggl[": "Biggl[\n\t${1:$TM_SELECTED_TEXT}\n\\Biggr]",
    "left{": "left\\{\n\t${1:$TM_SELECTED_TEXT}\n\\right\\}",
    "bigl{": "bigl\\{\n\t${1:$TM_SELECTED_TEXT}\n\\bigr\\}",
    "Bigl{": "Bigl\\{\n\t${1:$TM_SELECTED_TEXT}\n\\Bigl\\}",
    "biggl{": "biggl\\{\n\t${1:$TM_SELECTED_TEXT}\n\\biggr\\}",
    "Biggl{": "Biggl\\{\n\t${1:$TM_SELECTED_TEXT}\n\\Biggr\\}",
  },
```

### ■ 例 2

相互参照に用いる `\label{labelName}` と `\ref{labelName}` における `labelName` は `chp:abst` のような参照タイプと説明に分けると名前空間を分けることで `labelName` が干渉せず利便性が良いものになります。

たとえば、デフォルトでは `\label` が存在する状態で `\ref` するとサジェストがトリガーされるものの、`labelName` 以外にもいくつかの登録されているスニペットが表示されてしまいます。

したがって、次のように `eqn` を打つまでは `labelName` を上手くサジェストさせることが出来ない。明らかに関係のないスニペットがサジェストされてしまっています。

![referenceDefault](https://i.gyazo.com/951fd495853e3e3b26696b4b54a9b72e.gif)

次のように `chp:` などは打たずにスニペットから選択できるようにしてみます。

```json
  "latex-workshop.intellisense.commandsJSON.replace": {
    "label{}": "label{${1|eqn,tbl,fig,chp,sec,ssc|}:$2}$0",
    "ref{}": "ref{${1|eqn,tbl,fig,chp,sec,ssc|}:$2}$0",
  },
```

`\label` を打つと、`eqn:` などのリストが表示されるため、ちょっと楽になります。
また、`\ref` では初めから `eqn:` を選択する必要があるため、サジェストには関連する `labelName` のみが表示されます。ただし、`eqn:` の右側で `Ctrl+Space` する必要があります。

![referenceCustom](https://i.gyazo.com/d22a6e3bafa2b25bb6b4cdfa9f26c1b8.gif)

デフォルトのインテリセンスは `Ctrl+S` で保存したときにトリガーされるように指定しているため、上の GIF では `\label{eqn:euler}` を入力したあとに保存しています。

これを書いてから気付きましたが、`\label{${1|eqn:,tbl:,fig:,chp:,sec:,ssc:|}$2}$0` の方が良さそうです。（GIF を変更するのも面倒なので…）

<!--
■ 例 3

<samp>commands.json</samp> には `\cref` が含まれているため、`\usepackage{cleveref}` していなくても `\cref` がサジェストされる。（なぜか含まれている）

これをサジェストさせないようにするには、以下のようにする。

```json
  "latex-workshop.intellisense.commandsJSON.replace": {
    "cref{}": "",
    "cpageref{}": "",
  },
```

ただし、これらのコマンドは `\usepackage{cleveref}` することでインテリセンスがトリガーされる。
-->

## ○ 常にパッケージのインテリセンスを有効にする

パッケージのインテリセンスを `\usepackage` せずに常に読み込ませたい場合やパッケージとして存在しないものをインテリセンスとして導入したい場合には、以下のように設定しておきます。

```json
  "latex-workshop.intellisense.package.extra": [
    "amsmath",
  ],
```

上の例では `\usepackage{amsmath}` していなくても amsmath パッケージのインテリセンスを読み込ませることができます。

<!--
## ○ 新しいインテリセンスデータを作成する

<!--

``json
  "latex-workshop.intellisense.package.dirs": [
    "X:\\path\\to\\folder\\intellisense"
  ],
```

ここに設置したファイルはファイル名に応じて `\usepackage` した際に読み込まれて利用できるようになる。

今回は例としてパッケージ名を `enhancement-lw` として `enhancement-lw_cmd.json` と `enhancement-lw_env.json` を作成する。これで、`\usepackage{enhancement-lw}` とすることで、このファイルが読み込まれるようになる。（ただし、enhancement-lw パッケージは存在しない）

```
X:\path\to\folder\intellisense
  ├── enhancement-lw_cmd.json
  └── enhancement-lw_env.json
```

これらのファイルを作成する際には、きちんと JSON ファイルを作成する必要がある。JSON ファイルがきちんと作成されていないと読み込むことが出来ない。注意が必要。

今回、これらのファイルを作成する目的は、<samp>commands.json</samp> と <samp>environments.json</samp> に無い LaTeX のデフォルトコマンドを補うこととする。したがって、`enhancement-lw_cmd.json` と `enhancement-lw_env.json` は常に読み込ませておきたいので、次のようにしておく。

```json
  "latex-workshop.intellisense.package.extra": [
    "enhancement-lw",
  ],
```

※ 本来はこれらのインテリセンスデータは `\usepackage` や `\documentclass` によってトリガーされるべきだろう。
--\>

:::note warn
インテリセンスデータのファイルを作成する際には、きちんと JSON ファイルを作成する必要があります。JSON ファイルがきちんと作成されていないと読み込むことが出来ません。注意が必要になります。
:::

`*.json` は適当なディレクトリにまとめておいて、以下の設定でディレクトリを指定します。

```json
  "latex-workshop.intellisense.package.dirs": [
    "X:\\path\\to\\folder\\intellisense"
  ],
```

ここに設置したファイルはファイル名に応じて `\usepackage` した際に読み込まれて利用できるようになります。

今回は例として、常に利用するが LaTeX Workshop から提供されていないコマンド・環境のインテリセンスデータを作成してみまあしょう。このインテリセンスデータは `enhancement-lw` という架空のパッケージ名を付けて作成します。また、以下のディレクトリに配置します。

```
X:\path\to\folder\intellisense\enhancement-lw.json
```

今回、これらのファイルを作成する目的は、LaTeX Workshop から提供されない LaTeX のデフォルトコマンド・環境を補うことにあります。したがって、<samp>enhancement-lw.json</samp> は常に読み込ませておきたいので、次のようにしておきます。

```json
  "latex-workshop.intellisense.package.extra": [
    "enhancement-lw",
  ],
```

<!-- ※ 本来はこれらのインテリセンスデータは `\usepackage` や `\documentclass` によってトリガーされるべきだろう。 --\>

### ■ データフォーマット

データフォーマットは、パッケージの親パッケージ (`includes`) やパッケージのオプション (`options`) を記述することも出来ます。これによって、“親パッケージから提供されるのコマンドや環境のサジェスト” や “パッケージやコマンド・環境の key-val オプションのサジェスト” が表示されるようになります。

|    キー    |      値      | 説明                                                                         |
| :--------: | :----------: | :--------------------------------------------------------------------------- |
| `includes` |     配列     | パッケージによって読み込まれる他のパッケージ一覧                             |
|   `macros`   | オブジェクト | パッケージが提供するコマンドに関するオブジェクト群                           |
|   `envs`   | オブジェクト | パッケージが提供する環境に関するオブジェクト群                               |
| `options`  |     配列     | パッケージのオプション一覧 <br> `\usepackage` のオプションでサジェストされる |
| `keyvals`  |     配列     | コマンドや環境内で利用される key-val のセット                                |

<details>
<summary>今回、例として作成する <samp>enhancement-lw.json</samp>（折りたたみ）</summary>
<div>

```json
{
  "includes": [],
  "macros": {
    "textstyle": {},
    "scriptstyle": {},
    "scriptscriptstyle": {},
    "setcounter{}{}": {
      "snippet": "setcounter{${1:counter}}{${2:start number}}",
      "keyvalindex": 0,
      "keyvalpos": 0
    }
  },
  "envs": {},
  "options": [],
  "keyvals": [
    [
      "chapter",
      "section",
      "subsection",
      "subsubsection",
      "equation",
      "table",
      "figure"
    ]
  ]
}
```

</div>
</details>


<!--
### ■ \_cmd\.json

<details>
<summary>amsmath によるコマンドのスニペットの例（折りたたみ）</summary>
<div>

`amsmath_cmd.json` <sup>[[↗]](https://github.com/James-Yu/LaTeX-Workshop/blob/master/data/packages/amsmath_cmd.json)</sup> からいくつかの例を取り出してみる。

まずは [`\dfrac` の例](https://github.com/James-Yu/LaTeX-Workshop/blob/master/data/packages/amsmath_cmd.json#L57-L61) を見てみる。

```json
  "dfrac{}{}": {
    "command": "dfrac{numerator}{denominator}",
    "package": "amsmath",
    "snippet": "dfrac{${1:numerator}}{${2:denominator}}"
  },
```

また、`[]` によるオプション引数がある場合には、複数の設定を課している。
例として [`\cfrac[]{}{}` と `\cfrac{}{}` の例](https://github.com/James-Yu/LaTeX-Workshop/blob/master/data/packages/amsmath_cmd.json#L22-L31) を見てみる。

```json
  "cfrac[]{}{}": {
    "command": "cfrac[align]{numerator}{denominator}",
    "package": "amsmath",
    "snippet": "cfrac[${3:align}]{${1:numerator}}{${2:denominator}}"
  },
  "cfrac{}{}": {
    "command": "cfrac{numerator}{denominator}",
    "package": "amsmath",
    "snippet": "cfrac{${1:numerator}}{${2:denominator}}"
  },
```

</div>
</details>

`_cmd.json` では `command`、`package`、`snippet` の 3 つを指定する必要がある。

```json
  "object_name": {
    "command": "コマンドの説明",
    "package": "パッケージ名",
    "snippet": "スニペット"
  }
```

|     キー      | 説明                       |
| :-----------: | :------------------------- |
| `object_name` | スニペットの呼び出し名     |
|   `command`   | コマンドの説明             |
|   `package`   | パッケージ名               |
|   `snippet`   | 実際に実行されるスニペット |

> **例**：なぜか LaTeX Workshop で提供されていない LaTeX の基本的なコマンドを作成する。
>
> - `\textstyle`
> - `\scriptstyle`
> - `\scriptscriptstyle`
> - `\setcounter`

`\setcounter` では、よくカウンターとして利用する `chapter` や `section` などを候補として出るようにしている。

ファイル名は `enhancement-lw_cmd.json` として保存する。

```json
{
    "textstyle": {
        "command": "textstyle",
        "package": "enhancement-lw",
        "snippet": "textstyle"
    },
    "scriptstyle": {
        "command": "scriptstyle",
        "package": "enhancement-lw",
        "snippet": "scriptstyle"
    },
    "scriptscriptstyle": {
        "command": "scriptscriptstyle",
        "package": "enhancement-lw",
        "snippet": "scriptscriptstyle"
    },
    "setcounter{}{}": {
        "command": "setcounter{counter name}{start number}",
        "package": "enhancement-lw",
        "snippet": "setcounter{${1|chapter,section,subsection,subsubsection,equation,table,figure|}}{${2:start number}}"
    }
}
```

![enhancement-lw_cmd](https://i.gyazo.com/717e6f1a0798c75d1c89cf4417ce6f0d.png)

これで、`\scriptstyle` をサジェストすることが出来るようになった。
LaTeX Workshop デフォルトのインテリセンスとの見栄えの悪さもない。（上の画像例では中央の `\scriptsize` がデフォルトで提供されている）

### ■ \_env\.json

<ditails>
<summary>amsmath による環境のスニペットの例（折りたたみ）</summary>
<div>

`amsmath_env.json` <sup>[[↗]](https://github.com/James-Yu/LaTeX-Workshop/blob/master/data/packages/amsmath_env.json)</sup> から具体例として [`alignat[]{}` の例](https://github.com/James-Yu/LaTeX-Workshop/blob/master/data/packages/amsmath_env.json#L2-L7) と [`alignat{}` の例](https://github.com/James-Yu/LaTeX-Workshop/blob/master/data/packages/amsmath_env.json#L14-L19) を見てみる。

```json
  "alignat[]{}": {
    "name": "alignat",
    "detail": "alignat[alignment]{n}",
    "snippet": "[${2:alignment}]{${1:n}}",
    "package": "amsmath"
  },
  "alignat{}": {
    "name": "alignat",
    "detail": "alignat{n}",
    "snippet": "{${1:n}}",
    "package": "amsmath"
  },
```

</div>
</details>

`_env.json` では `name`、`detail`、`snippet`、`package` の 4 つを指定すれば良い。

```json
  "object_name": {
    "name": "環境の説明",
    "detail": "サジェスト表示",
    "snippet": "スニペット",
    "package": "パッケージ名"
  }
```

|     キー      | 説明                                          |
| :-----------: | :-------------------------------------------- |
| `object_name` | スニペットの呼び出し名                        |
|    `name`     | 環境の説明                                    |
|   `detail`    | サジェスト表示                                |
|   `snippet`   | `\begin{env_name}` に続いて実行するスニペット |
|   `package`   | パッケージ名                                  |

コマンドと同じように自作環境のためのインテリセンスデータを作成すれば良いだろう。

> **例**：description 環境のような `\item[]` を挿入したい環境を作成する。

ファイル名は `enhancement-lw_cmd.json` として保存する。

```json
{
    "itemlist": {
        "name": "itemlist",
        "detail": "itemlist",
        "snippet": "\n\t\\item[$1] $0",
        "package": "enhancement-lw"
    }
}
```
--\>

### ■ コマンドと環境

コマンドは `"macros"` オブジェクト、環境は `"envs"` オブジェクトに記述されます。各コマンド・環境ともにオブジェクトを持つメンバーによって記述されますが、オブジェクト内のキーは任意となっています。

#### ▽ `"macros"` オブジェクト

`"macros"` オブジェクト内で利用されるキー：
|      キー       |   値   | 説明                                                                                                                |
| :-------------: | :----: | :------------------------------------------------------------------------------------------------------------------ |
|    `command`    | 文字列 | コマンド名（オブジェクトキーと異なる場合に利用）                                                                    |
|    `snippet`    | 文字列 | コマンドのスニペット                                                                                                |
|    `option`     |  配列  | `\usepackage` で特定のオプションが有効になっているときのみサジェストされるコマンド                                  |
|  `keyvalindex`  |  数値  | `{}` で囲まれる引数に `keyvals` をサジェストする際に利用。<br> 最左の `[]` または `{}` が `0`、その右が `1` …となる |
|   `keyvalpos`   |  数値  | コマンドに渡される可能性のある key-val。 <br> package.keyvals のナンバリングで指定する                              |
|    `details`    | 文字列 | 記号等の詳細を説明                                                                                                  |
| `documentation` | 文字列 | コマンドの説明                                                                                                      |

> **例**：なぜか LaTeX Workshop で提供されていない LaTeX の基本的なコマンドを作成する。
>
> - `\textstyle`
> - `\scriptstyle`
> - `\scriptscriptstyle`
> - `\setcounter`

`\setcounter` では、よくカウンターとして利用する `chapter` や `section` などを候補として出るようにしています。

```json
  "macros": {
    "textstyle": {},
    "scriptstyle": {},
    "scriptscriptstyle": {},
    "setcounter{}{}": {
      "snippet": "setcounter{${1:counter}}{${2:start number}}",
      "keyvalindex": 0,
      "keyvalpos": 0,
    }
  },
  "keyvals": [
    [
      "chapter",
      "section",
      "subsection",
      "subsubsection",
      "equation",
      "table",
      "figure"
    ]
  ]
```

#### ▽ `"envs"` オブジェクト

`"envs"` オブジェクト内で利用されるキー：
|     キー      |   値   | 説明                                                                                                                |
| :-----------: | :----: | :------------------------------------------------------------------------------------------------------------------ |
|    `name`     | 文字列 | 環境名（オブジェクトキーと異なる場合に利用）                                                                        |
|   `snippet`   | 文字列 | 環境のスニペット                                                                                                    |
|   `option`    |  配列  | `\usepackage` で特定のオプションが有効になっているときのみサジェストされるコマンド                                  |
| `keyvalindex` |  数値  | `{}` で囲まれる引数に `keyvals` をサジェストする際に利用。<br> 最左の `[]` または `{}` が `0`、その右が `1` …となる |
|  `keyvalpos`  |  数値  | コマンドに渡される可能性のある key-val。 <br> package.keyvals のナンバリングで指定する                              |

> **例**：itemize 環境 [<sup>[↗]</sup>][dataItemize]（LaTeX Workshop で提供されていない良い例の環境が思いつかなかった）

[dataItemize]: https://github.com/James-Yu/LaTeX-Workshop/blob/b2aac14c7f684ae7241c5c3dc98d5eab30363179/data/packages/latex-document.json#L561-L564

```json
  "itemize\\item": {
    "name": "itemize",
    "snippet": "\\item"
  },
```

### ■ 親パッケージとオプション

LaTeX では、ユーザーが読み込ませたパッケージから他のパッケージが読み込ませるようにしているパッケージが数多くあります。LaTeX Workshop のインテリセンスデータには、これを理解して、インテリセンスを提供することが出来ます。

また、パッケージに関するオプションも数多くあり、このインテリセンスを提供することも出来ます。
-->

## ○ TeX ツリー内の独自パッケージを読み込む

TeX ツリー内に `\newcommand` などで構成された独自ファイル (\.sty) を `\usepackage` する場合では、LaTeX Workshop はこのファイルを読むことは出来ません。

このファイルを読ませてインテリセンスを提供させるには、次のようにディレクトリを知らせることが出来ません。

```json
  "latex-workshop.latex.texDirs": [
    "X:\\path\\to\\texlive\\texmf-local\\tex\\latex\\local"
  ]
```

しかしながら、LaTeX Workshop の自動的な読み込みよりも <samp>*.json</samp> を作成した方が個人的には良いようにも思います。

## ○ 複数の同一名コマンドスニペットの制御

コマンドには複数のオプション引数を与えられる場合があり、インテリセンスでは複数のパターンを同時に表示するようになっています。

これが長いと感じる場合は以下の設定で `false` とすれば良いでしょう。

```json
  "latex-workshop.intellisense.optionalArgsEntries.enabled": false,
```

## ○ `@` サジェスト

`@` によってトリガーされるサジェストが複数あります。代表的なものとして、`@a` で `\alpha` が挿入されるギリシャ文字のサジェストがあります。

これらの詳細は、特に次のページを参照すると良いでしょう。

- [Insert Greek letters](https://github.com/James-Yu/LaTeX-Workshop/wiki/Intellisense#inserting-greek-letters)
- [Handy mathematical helpers](https://github.com/James-Yu/LaTeX-Workshop/wiki/Intellisense#handy-mathematical-helpers)

また、これらのサジェストは以下のファイルで設定されています。

- <samp>at-suggestions.json</samp> <sup>[[↗]](https://github.com/James-Yu/LaTeX-Workshop/blob/master/data/at-suggestions.json)</sup>

`@` サジェストはこれまでのインテリセンスとは別となっているようです。

### ■ トリガー文字の変更

`@` によるトリガーを以下の設定から変更できます。もしも、`@` が押下しづらい場合には、適当に変更すると良いでしょう。（半角スペースをトリガーに指定することも出来るゾ）

```json
  "latex-workshop.intellisense.atSuggestion.trigger.latex": "@",
```

ただし、トリガー文字は `::` などの 2 文字で構成することには不向きらしいです。（`Ctrl+Space` で無理やりサジェストを表示させることは出来る）また、` あ ` 等をトリガー文字に指定しても問題ないようですが、タイプするのが面倒になるので避けた方が良いかも知れません。

### ■ サジェストの変更と追加

`latex-workshop.intellisense.commandsJSON.replace` と同じように構成を変更できます。ただし、これによって可能な設定は削除を含む上書きと新たなサジェストの追加になります。

```json
  "latex-workshop.intellisense.atSuggestionJSON.replace": {},
```

上書きする場合には、<samp>at-suggestions.json</samp> のスニペットを変更するため、設定されている `prefix` を知る必要があります。（<samp>at-suggestions.json</samp> 内では `prefix` がスニペットの呼び出しとなっている）

新たなサジェストは、既存のサジェスト `prefix` に存在しないものを利用する必要があります。また、新たなサジェストの `prefix` はトリガー文字がどのようなものであれ `@` から始める必要があることに注意してください。

### ■ 例

[\# 既存のインテリセンスを変更する](#-既存のインテリセンスを変更する) の [\# 例 1](#-例-1) と同じように、`@(` などの出力を複数行に変更する場合には次のようにします。

```json
  "latex-workshop.intellisense.atSuggestionJSON.replace": {
    "@(": "\\left(\n\t${1:$TM_SELECTED_TEXT}\n\\right)",
    "@[": "\\left[\n\t${1:$TM_SELECTED_TEXT}\n\\right]",
    "@{": "\\left{\n\t${1:$TM_SELECTED_TEXT}\n\\right}",
  },
```

この他にも、`@;` から呼び出される `\dot` に `$TM_SELECTED_TEXT` を含めるなどしても有益でしょう。

また、括弧の高さが手動調整の `@` サジェストを追加したい場合には、`prefix` を `@(b` などとすれば対応できるでしょう。

```json
  "latex-workshop.intellisense.atSuggestionJSON.replace": {
    "@(b": "\\bigl(\n\t${1:$TM_SELECTED_TEXT}\n\\bigr)",
    "@(B": "\\Bigl(\n\t${1:$TM_SELECTED_TEXT}\n\\Bigl)",
    "@(bg": "\\biggl(\n\t${1:$TM_SELECTED_TEXT}\n\\biggr)",
    "@(Bg": "\\Biggl(\n\t${1:$TM_SELECTED_TEXT}\n\\Biggr)",
    "@[b": "\\bigl[\n\t${1:$TM_SELECTED_TEXT}\n\\bigr]",
    "@[bg": "\\biggl[\n\t${1:$TM_SELECTED_TEXT}\n\\biggr]",
    "@[B": "\\Bigl[\n\t${1:$TM_SELECTED_TEXT}\n\\Bigl]",
    "@[Bg": "\\Biggl[\n\t${1:$TM_SELECTED_TEXT}\n\\Biggr]",
    "@{b": "\\bigl\\{\n\t${1:$TM_SELECTED_TEXT}\n\\bigr\\}",
    "@{B": "\\Bigl\\{\n\t${1:$TM_SELECTED_TEXT}\n\\Bigl\\}",
    "@{bg": "\\biggl\\{\n\t${1:$TM_SELECTED_TEXT}\n\\biggr\\}",
    "@{Bg": "\\Biggl\\{\n\t${1:$TM_SELECTED_TEXT}\n\\Biggr\\}",
  }
```

また、これと同じように figure 環境や table 環境を作成することもできます。

```json
  "latex-workshop.intellisense.atSuggestionJSON.replace": {
    "@figure": "\\begin{figure}[htb]\n\t\\centering\n\t\\includegraphics[width=.8\\linewidth]{$0}\n\t\\caption{$1}\n\t\\label{fig:$2}\n\\end{figure}",
    "@table": "\\begin{table}[htb]\n\t\\centering\n\t\\caption{$1}\n\t\\label{tbl:$2}\n\t${0:TM_SELECTED_TEXT}\n\\end{table}",
  }
```

当たり前ながら VSCode デフォルトのスニペットで作成した方が簡単ではありますが、サジェスト時の取り扱いが少しだけ変わります。こちらの方の使い勝手が良い可能性もあります。1 行で収める必要があるため、少し面倒かも知れません。

# 参考

- [Intellisense · James-Yu/LaTeX-Workshop \- GitHub Wiki](https://github.com/James-Yu/LaTeX-Workshop/wiki/Intellisense)
    - [Commands starting with `\`](https://github.com/James-Yu/LaTeX-Workshop/wiki/Intellisense#commands-starting-with-)
    - [`@` suggestion](https://github.com/James-Yu/LaTeX-Workshop/wiki/Intellisense#-suggestions)
- [LaTeX-Workshop/data at master · James-Yu/LaTeX-Workshop](https://github.com/James-Yu/LaTeX-Workshop/tree/master/data)
- [LaTeX-Workshop/dev/README.md at master · James-Yu/LaTeX-Workshop](https://github.com/James-Yu/LaTeX-Workshop/blob/master/dev/README.md#ctanpkglist.py)

# 余談

デフォルトで数多くのインテリセンスを提供しているものの、ちょっとだけ物足りないと感じるところもあります。これによって、インテリセンスを各自で拡充させることが出来るため、よりよい編集環境を築けるのではないでしょうか。

パッと見て、jlreq 用のインテリセンスは提供されていないため、これを作ってみても良いだろうなと思います。

もしも LaTeX Workshop のインテリセンスデータを追加したい場合は、LaTeXing の cwl にコミットすると、それを利用する LaTeX Workshop にも反映されるようになるでしょう。

# 追記

- 2022/04/03: ver.8.24.0 以降で追加された `@` サジェストの変更を追加しました。また、壊滅的な日本語をいくつか修正しました
- 2022/07/29: インテリセンス更新のタイミングについて追記。例で示している <samp>enhancement.json</samp> を enhancement パッケージが存在する可能性を避けるため <samp>enhancement-lw.json</samp> に変更。`@` サジェストの例を追加。その他、軽微修正
- 2022/12/13: インテリセンスデータについて、非互換的な更新の可能性について追記
- 2023/01/03: インテリセンスデータの新しいデータフォーマットに対応。旧フォーマットに関する記述は非表示にしている
- 2023/01/09: インテリセンスデータについて、非互換的な更新について追記
- 2024/02/10: JSON を Python で生成する具体的な記事が公開されたのでリンクしました
- 2024/10/01: JSON を自作する部分を削除しました