Quantcast
Channel: Vimタグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 5608

Atom の PHP 補完を vim-lsp で使う

$
0
0

Vim で PHP を書くときは vim-lspで Intelephense を使っているのですが、プロプライエタリなソフトウェアなのでサーバサイドのコードが公開されていません。Intelephense のウェブサイトはあまり親切ではなく、初めてインストールしたときは正しく動かせているのかよく分からなかった事を覚えています。
そのため OSS の PHP LSP を探していたところ Serenataというソフトウェアを見つけました。

Serenata は Atom エディタのプラグインとして公開されていたようです。サーバ型の Serenata 本体と、Atom プラグインの php-ide-serenataの2つで構成されています。バージョン4までは Atom エディタ用ですがバージョン5で Language Server Protocol をサポートしたようです。
対応している LSP の機能は Language Server Protocol Support Table のページで確認できます。

php-ide-serenataの動作画面

php-ide-serenata.png

今回はこの Serenata をvim-lspから使えるように設定してみました。

vim-lsp の動作画面
serenata_completion.png

Serenata はTCPソケットしかサポートされていなかったので、vim-lsp の標準入出力とつなげるために socatコマンドを使いました。
ひとまず vim 側での補完やホバー表示ができるところまでは確認したのですが、速度面で難があったり、vim-lsp の起動initialize/終了exitとうまく連動できないので実用レベルには至りませんでした。 もう少し調査して使えるようにしたいのですが一旦ここまでの記録を公開します。

事前準備

vim-lsp が動く状態になっていることが前提です。その他に必要なソフトウェアは以下の通りです。

  • PHP 7.1+
    • mbstring
    • xml
    • libxml
    • dom
    • openssl
    • pdo_sqlite
  • socatコマンド
  • vim
    • vim-lsp

socatコマンドがインストールされているか確認してください。macOS は brew でインストール可能です。

$ which socat
/usr/local/bin/socat
$ socat -V
socat by Gerhard Rieger and contributors - see www.dest-unreach.org
socat version 1.7.3.3 on May 11 2019 02:21:21
...
$ brew install socat # インストールされていなければ

Serenata の導入

1. 実行可能な PHAR 形式のファイルをダウンロード

Serenata サーバをダウンロードしてください。インストール方法はいくつかありますが実行可能な PHAR 形式のファイルが簡単です。PHAR compatible with PHP 7.xを選択してください。

2. ポート 11111で起動

Serenata サーバをポート 11111で起動してみましょう。Serenata はソースコードの解析結果をデータベースに保存します。デフォルト設定では SQLite をインメモリで使用します。メモリ使用量が多いので phpの起動オプションでメモリを多めに確保します。

$ php -dmemory_limit=2048M ~/bin/serenata.phar --uri tcp://127.0.0.1:11111
Starting server bound to socket on URI tcp://127.0.0.1:11111...

正常に起動できれば Starting server bound ....と表示されて LISTEN 状態になります。

3. 動作確認

動作確認のために initializeメソッドを実行してみます。socatを使って Serenata サーバのポート 11111に送信します。Content-Lengthには JSON のバイト数が書かれていますので、rootPathrootUriを変更したら Content-Lengthも忘れずに変更してください。1バイトでも合わないと正しく動作しません。
また、保存するファイルのフォーマットにも注意してください。LSP の仕様で改行コードは CRLF、ファイル最終行の行末には改行を含めないようにしてください。

serenata.jsonrpc
Content-Length:1429{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":19002,"rootPath":"/Users/foobar/src/foobar/foobarbazfo/","rootUri":"file:///Users/foobar/src/foobar/foobarbazfo/","workspaceFolders":[],"capabilities":{"workspace":{"applyEdit":true,"configuration":false,"workspaceEdit":{"documentChanges":true},"workspaceFolders":false,"didChangeConfiguration":{"dynamicRegistration":false},"didChangeWatchedFiles":{"dynamicRegistration":false},"symbol":{"dynamicRegistration":false},"executeCommand":{"dynamicRegistration":false}},"textDocument":{"synchronization":{"dynamicRegistration":false,"willSave":true,"willSaveWaitUntil":true,"didSave":true},"completion":{"dynamicRegistration":false,"completionItem":{"snippetSupport":true,"commitCharactersSupport":false},"contextSupport":true},"hover":{"dynamicRegistration":false},"signatureHelp":{"dynamicRegistration":false},"references":{"dynamicRegistration":false},"documentHighlight":{"dynamicRegistration":false},"documentSymbol":{"dynamicRegistration":false,"hierarchicalDocumentSymbolSupport":true},"formatting":{"dynamicRegistration":false},"rangeFormatting":{"dynamicRegistration":false},"onTypeFormatting":{"dynamicRegistration":false},"definition":{"dynamicRegistration":false},"codeAction":{"dynamicRegistration":false},"codeLens":{"dynamicRegistration":false},"documentLink":{"dynamicRegistration":false},"rename":{"dynamicRegistration":false}},"experimental":{}}}}

動作確認するだけならパスの変更は不要です

実行して Content-Lengthで始まるレスポンスが返ってくれば成功です。

$ socat stdio tcp4:127.0.0.1:11111,shut-none < serenata.jsonrpc
Content-Length: 951

{"jsonrpc":"2.0","id":0,"result":{"capabilities":{"textDocumentSync":{"openClose":false,"change":1,"willSave":false,"willSaveWaitUntil":false,"save":{"includeText":true}},"hoverProvider":true,"completionProvider":{"resolveProvider":false,"triggerCharacters":null},"signatureHelpProvider":{"triggerCharacters":["(",","]},"definitionProvider":true,"typeDefinitionProvider":false,"implementationProvider":false,"referencesProvider":false,"documentHighlightProvider":true,"documentSymbolProvider":true,"workspaceSymbolProvider":false,"codeActionProvider":false,"codeLensProvider":{"resolveProvider":true},"documentFormattingProvider":false,"documentRangeFormattingProvider":false,"documentOnTypeFormattingProvider":null,"renameProvider":false,"documentLinkProvider":null,"colorProvider":false,"foldingRangeProvider":false,"executeCommandProvider":null,"workspace":{"workspaceFolders":{"supported":false,"changeNotifications":false}},"experimental":null}}}

vim-lsp 設定

1. lsp#register_serverの設定

Serenata が正しく動いていることが確認できたので vim-lsp の設定を追加してください。

auUser lsp_setup call lsp#register_server({    \'name':'serenata',    \'cmd':{server_info->['socat','stdio','tcp4:127.0.0.1:11111,shut-none']},    \'initialization_options':{"rootPath":"/Users/foobar/src/foobar/foobarbazfo/","rootUri":"file:///Users/foobar/src/foobar/foobarbazfo/"},    \'whitelist':['php'],    \'workspace_config':{'serenate':{    \'files.associations':['*.php'],    \}},    \})

2. 動作確認

Serenataサーバを起動した状態で vim で PHP のファイルを開きます。vim-lsp が Serenata サーバに正しく接続できれば :LspStatusの実行結果が serenata: runningになります。vim-lsp と Serenata の起動・終了の仕様に齟齬があるので、vim を終了した場合は Serenata サーバも再起動しないと LspStatusの結果が failedになります。

まとめ

Serenata はサーバ型なので LSP の exitメソッド実行されても終了せず、vim-lsp が再度 initializeメソッドを実行するとエラーになります。速度も Atom エディタで使うより遅いのでもう少し改善の余地がありそうです。
また成果があれば公開します。

その他のスクリーンショット

クラス名の補完
serenata_completion_type.png
メソッド補完
selenata_completion_method.png
クラスのホバー表示
serenata_hover_type.png
メソッドのホバー表示
serenata_hover_method.png


Viewing all articles
Browse latest Browse all 5608

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>