Qt 6.6で導入された「QML Language Server」には、新たなコードナビゲーション機能が加わっています。本稿ではQML Language Serverとは何か、また使い方についてご紹介します。
QML Language ServerはQMLの言語モデルで、多くのエディタで利用可能です。
具体的には、警告やエラーの表示、高度なコードナビゲーション、コードの整形などが行えます。QML Language Serverについてより詳しく知りたい方は、最新(執筆時点での)ドキュメントページ(英語)をぜひご参照ください。
QML Language Serverを実際に使用するには、Language Server Protocol(LSP)が必要です。
それでは、お好みのテキストエディタ(LSP対応済み)を使用して、QML Language Serverの新機能を体験してみましょう。
セットアップ手順はエディタによって異なりますが、この記事ではVS CodeでのQML Language Serverの設定方法についてご紹介します。
Qt Creator 11(執筆時点での最新バージョン)では、QML Language Serverの機能はデフォルトで用意されています。「環境設定(英語)」から「言語クライアント」にQML Language Serverを追加したり、「Qt Quick」設定でqmllsサポートをオンにすることはできますが、これらは内部で動いている実装を上書きするわけではありません。この仕様は、QML Language Serverが今後進化するにつれて変わる可能性があります。
今回の記事のために、QML Language Serverのいくつかの機能を試せるサンプルプロジェクト(gitレポジトリ)を用意しました。
下記の通りクローンしてください:
git clone https://git.qt.io/Sami.Shalayel/demoforqmllswhatsnew66.git
ビルド用のフォルダを作成して、そのフォルダ内に移動してから以下の通りプロジェクトのビルド設定を行ってください:
mkdir build-demoforqmllswhatsnew66-debug
<path/to/QtInstallation>/bin/qt-cmake -S ../demoforqmllswhatsnew66 -B . -G Ninja
この記事では、こちら(gitレポジトリ)の試験的な非公式拡張機能を搭載したVS Codeを使用しています。
拡張子なしで言語サーバーを使えるエディタもありますので、その点はお忘れなく。中には、バイナリのパスと使うファイル拡張子だけを設定すればいいものもあります。そういった場合は、この手順を飛ばして次に進んでも大丈夫です。
それができたら、次の手順でリポジトリをクローンしてください:
git clone https://git.qt.io/Sami.Shalayel/qmlls-vscode.git
qmlls-vscodeフォルダに移動して、以下のコマンドで必要な依存関係をダウンロード、インストールします:
npm install && npm run compile
そして、以下のコマンドで、現在のフォルダ内でVS Codeを起動することが可能になります。
code .
VS Codeのウィンドウが開いたら、非公式のVS Code拡張プロジェクトが表示されるようになります(次セクション参照)。
VS Codeが開いたら、そこでclient/src/extension.tsファイルを開きます:
その中に、以下のようなコードが見つけられるはずです:
const serverExecutable : Executable = {
command: "sh",
args: [ '-c', 'tee /tmp/qmllsInput | $HOME/projects/qt5-build/qtbase/bin/qmlls | tee /tmp/qmllsOutput'],
// prints VSCode commands to qmlls into qmllsInput file and
// qmlls responses into qmllsOutput file
};
この箇所には、実際の'qmlls'バイナリを指定する必要があります。
公式のインストーラを用いてQtをインストールした場合、`<QtInstallationPath>/bin` フォルダ内に'qmlls'バイナリが存在するはずです。
Qt 6.6またはdevブランチを手動でコンパイルした場合、`ninja qtdeclarative_src qmlls`コマンドを実行することでバイナリを生成できます。このバイナリはインストールフォルダ内の`bin`フォルダに格納されており、開発ビルドの場合には`qtbase/bin/qmlls`に位置しています。
私のマシンでは、バイナリは`/Users/sami/Qt/6.6.0/macos/bin/qmlls`に位置しており、`/Users/sami/Qt/`はQtインストーラーで指定したインストールパスです。
また、QML Language Serverが現在のプロジェクトのビルドフォルダを認識する必要があるため、結果的には以下のように書き換えます:
const serverExecutable : Executable = {
command: "/Users/sami/Qt/6.6.0/macos/bin/qmlls",
args: [ '--build-dir', '<path/to/build-demoforqmllswhatsnew66-debug>'],
};
コマンドライン引数が使用できない場合、QML Language Serverにビルドディレクトリを指定する方法については、公式ドキュメント(英語)をご参照ください。
もし最初に紹介したリンク先のサンプルプロジェクトを使用しない場合、使用するプロジェクトのビルドディレクトリを代わりに指定してください。
プロジェクトで定義されたQMLモジュールは、`qmldir`が`path/to/build-directory/ModuleName/qmldir`に存在する場合のみ認識されます。
QML Language Serverは、どのビルドディレクトリをプロジェクトのQMLモジュール検索に使用するかに関するメッセージを出力するはずです。
QML Language Server拡張の設定が完了したら、スクリーンショットで示されているように、Baptist BENOIST製のVS Code用QML拡張をインストールしてください:
以上で設定は完了です!
ファイルを保存した後、"play"ボタンをクリックしてプロジェクトを実行してください:
QML Language Server用に設定したエディタでQMLプロジェクトを開いてください。
Ctrl+O(Windows)またはCommand+O(Mac)を使用してプロジェクトのフォルダを選択し、VS Codeで開くことができます。
`Main.qml`ファイルを開くと、最初に以下のような警告メッセージが表示されるはずです:
警告が表示されない場合、無効なQMLドキュメントが存在するか、またはQML Language Serverが正確にセットアップされていない可能性があります。先に「VS CodeでのQML Language Serverのセットアップ」で説明した手順を見落としているかもしれません。
QML Language Serverは、ビルドディレクトリを調査してプロジェクト内のQMLモジュールを検出します。`build-demoforqmllswhatsnew66-debug`フォルダ内で`ninja`コマンドを実行し、プロジェクトをビルドしてください。
プロジェクトのビルドが完了したら、一度エディタを閉じて再度開きます。これにより、QML Language Serverが不足しているモジュールのロードを試み、関連する警告が消えているかを確認してください:
QML Language Serverがまだ動作していることを確認するために、未定義の`QmlComponent`を追加してみました。このコンポーネントに対する定義を追加することで、警告を解消できます:
component UnknownComponent: Item {} // add this line before the line with 'UnknownComponent {}'
この行を追加することで、プロジェクトを再コンパイルしたり、手動で`qmllint`を実行してファイルにエラーがないかチェックする必要がなくなるでしょう。QML Language Serverが警告の更新を自動で行ってくれるからです。
QML Language Serverは現在も開発中であり、クラッシュやバグが発生する可能性があります。クラッシュやバグの報告はこちらからお願いします。
スクリーンショットを撮影する目的で、私はQML Language Serverの各種機能をコンテキストメニューから起動することにしました。
6.6から導入されたQML Language Serverの新機能の一つとして、特定のオブジェクトの定義を検索する機能があり、これは6.7でさらに改善される予定です。例えば、`myItem.i`がどこで定義されているのか知りたい場合があります。それは、誰かが全てのプロパティの名前を'i'と設定したためです。`myItem.i`の`i`を右クリックして、'Go to definition'を選択してください:
すると、QML Language Serverが動作し、エディタは`i`のプロパティ定義の位置にジャンプします:
今後、QML Language Serverの機能が拡充されるにつれて、右クリックメニューから実行できる操作も増える予定です。
これは、例えば、`id`に対しても同様に有効です:
これにより、上方に存在する`myItems`の定義を見つけることができます:
ぜひご自身で試してみてください!QMLのコードを書き、QML Language Serverにその定義を探してもらいましょう。何か予期せぬ動作があれば、こちらで報告をお願いします。
この機能は前述のものと似ているように思えますが、例えば`myComponent`のようなプロパティの型の定義を探すことができます:
すると、`myComponent`プロパティの型に関する定義が表示されるでしょう:
エディターから離れることなく`qmlformat`で書式を整えるには、コードの任意の位置で右クリックし、「文書の書式設定」を選択してください:
これにより、きれいに整えられたQMLファイルが表示されるはずです:
QML Language Server 6.6のもう一つの新機能として、シンボルの使用法を検索する機能があります。例えば、`f`関数が`i`というプロパティを頻繁に使用する場合、QML Language Serverに現在のQMLファイル内での`i`プロパティの出現回数を全て検索してもらうことができます。
以下のような使用例が表示されるはずです:
`i`の定義も使用例のリストに含まれていますが、QML Language Serverは`f`関数の内部で定義されたJavaScriptの識別子`i`と、`while-loop`のブロック内で定義されたJavaScriptの識別子`i`を区別している点に注意してください。興味があれば、内側の識別子の使用法も確認してみてください:
その結果は以下のようになるでしょう:
また、`myItems`のような特定の`id`の使用法を探すことも可能です:
その結果は以下のようになるでしょう:
QML Language Server 6.6では、いくつかの制限事項があることが知られています。
現在のところ、メソッド名はサポートされていないため、QML Language Serverはメソッドへの参照を検出すること、またはメソッドの定義にジャンプすることはできません。
ループ (for、while など) などの一部の JavaScript 言語構造は 6.6 には実装されておらず、QML Language Serverではサポートされていません。このような場合、クラッシュする (こちらで報告してください) または定義や使用法の問い合わせに対して不完全な情報または情報が表示されない場合があります。
コードに未実装の構文を使用している場合は、ほとんどの JavaScript 構文をサポートしている dev 版の QML 言語サーバーを使用することを検討してください。
LSP 機能のシンボル名変更は、QML Language Serverの 6.7 で利用可能になります。開発版のQML Language Serverを使用している場合は、現在の機能を確認できます。
現在の QML Language Server のバージョンでは、ファイル全体をフォーマットできますが、ファイルの一部をフォーマットすることはできません。将来的に、ファイル全体ではなく、選択したコードのみをフォーマットできるようになる予定です。
QML 言語サーバーについて多くのことを学べたと思います。QML 言語サーバーに興味を持っていただき、ご自身のコードで試してみて、バグやクラッシュが発生した場合は、6.6 または dev の QML 言語サーバーのバグ報告ページ こちら にバグを報告していただければ幸いです。