5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2022-03-03

LaTeX Workshop | James Yu
投稿時; ver.8.23.0 (2022/3 現在)、最終更新時; ver.10.4.1

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

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

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

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

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

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

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

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

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

chaplin

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

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

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

{
  "[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 ミリ秒となっています。

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

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

○ インテリセンスデータ

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

LaTeX-Workshop/data at master · James-Yu/LaTeX-Workshop

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

  • デフォルトのインテリセンスデータ
  • パッケージや文書クラスごとのインテリセンスデータ(data/packages/ [↗] 以下に含まれている)
    • *.json
    • class-*.json

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

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

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

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

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

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

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

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

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

commands.json のコマンドスニペットの例(折りたたみ)

commands.json\label{} の例 を見てみましょう。

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

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

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

■ 例 1

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

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

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

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

  "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} における labelNamechp:abst のような参照タイプと説明に分けると名前空間を分けることで labelName が干渉せず利便性が良いものになります。

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

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

referenceDefault

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

  "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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@ サジェスト

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

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

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

  • at-suggestions.json [↗]

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

■ トリガー文字の変更

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

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

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

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

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

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

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

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

■ 例

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

  "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 などとすれば対応できるでしょう。

  "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 環境を作成することもできます。

  "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 行で収める必要があるため、少し面倒かも知れません。

参考

余談

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

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

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

追記

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

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
  3. You can use dark theme
What you can do with signing up
5
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?