neovim で Language Server Protocol を利用してコード支援機能を実現してみる

この記事はMisoca+弥生 Advent Calendar 2019の2日目です。

先月末、 昨年に続いて、Safecast Hackathon に参加してきました。昨年のHackahtonぐらいから再開したポケモンGoはまだ細々と続けています。最近、毎週50kmの週間リワードも貰いますが、ボールが使い切れなくて困っています。

今回は、solargraph という ruby の Language Server を使って、neovim でコード補完や定義への移動をできるようにしてみましたので、その設定方法を紹介します。

Language Server Protocol (LSP) とは?

The Language Server protocol is used between a tool (the client) and a language smartness provider (the server) to integrate features like auto complete, go to definition, find all references and alike into the tool

Langserver.org  でこのように定義されています。Language Server Protocol は、コード補完、定義への移動、参照箇所の検索というようなコード支援に必要な情報を提供する言語サーバーとその情報を受け取る開発ツール(クライアント)の間のやり取りを定めたものです。

 Rubyの場合、vim-ruby (vim)、ruby-mode (emacs)、vscode-ruby (vscode) のように、コード支援機能は、開発ツールごとに実装されています。LSP を使うことで、言語サーバーがコード支援に必要な情報を提供して、開発ツールはクライアントとてして、その情報を受け取ることで、コード支援機能を提供することができるようになります。

Solargraph (言語サーバー) の設定

solargraph は、Ruby向けの言語サーバーです。コード補完やRubyの標準クラスの文書などの情報を提供します。

 

f:id:eitoball:20191202093629p:plain

solargraph は rubygem として提供されているので、gem コマンドで簡単にインストールできます。

$ gem install solargraph

デフォルトでは、ruby 2.2 向けの「core」(標準クラスのドキュメント)が同梱されています。list-cores コマンドで確認できます。

$ solargraph list-cores
2.2.2

使用しているrubyのバージョンをcoreは、download-core コマンドで取得します。available-cores で取得可能なcoreを表示することができます。

$ solargraph available-cores
2.6.1
2.6.0
2.5.3
...
$ solargraph download-core 2.6.1

download-core でバージョンを指定しない場合は、使用している(パスが通っている)rubyのバージョンにあうcoreを取得します。

プロジェクトで利用しているrubygemの文書を表示したい場合は、プロジェクトのルートディレクトリに移動して、bundle コマンドを実行します。

$ solargraph bundle

Gemfile を読み、必要な文書を取得します。

最後に config コマンドで設定ファイルを作成します。プロジェクトのルートディレクトリに移動して実行します。

$ solargraph config

実行したディレクトリに.solargraph.yml というファイルが作成されます。 Rails アプリケーションの場合、デフォルトの設定で問題ないと思います。興味がある方は、こちら を参照して下さい。

vim-lsp (クライアント)の設定

今回は、neovim で LSP クライアントとして、vim-lsp を使用します。async.vim も必要です。それぞれのプラグイン管理方法に応じた方法で2つのプラグインを追加します。

vim-lsp の Wikiページ にあるように ~/.config/nvim/init.vim に以下を追加します。

if executable('solargraph')
    " gem install solargraph
    au User lsp_setup call lsp#register_server({
        \ 'name': 'solargraph',
        \ 'cmd': {server_info->[&shell, &shellcmdflag, 'solargraph stdio']},
        \ 'initialization_options': {"diagnostics": "true"},
        \ 'whitelist': ['ruby'],
        \ })
endif

'initialization_options': {"diagnostics": "true"}, は、デバッグ用のログを出力するためなので、vim-lsp を正しく動作するように設定できたら、削除して良いと思います。。

次にコード補完のための設定をします。今回は、asyncomplete.vim を使います。このプラグインasyncomplete-lsp.vim を追加します。そして、

inoremap <silent><expr> <TAB>
  \ pumvisible() ? "\<C-n>" :
  \ <SID>check_back_space() ? "\<TAB>" :
  \ asyncomplete#force_refresh()
inoremap <expr><S-TAB> pumvisible() ? "\<C-p>" : "\<C-h>"

という設定を ~/.config/nvim/init.vim に追加すれば、コード補完ができるようになります。このように文字を入力すると候補が表示されます。Ctrl-N や Ctrl-P を使って、候補から選択します。

f:id:eitoball:20191202031756p:plain

コマンドモードで:LspPeekDefinitionと入力すればカーソル上のクラスやメソッドの定義をポップアップに表示することができます。

f:id:eitoball:20191202032214p:plain

LspDefinition の場合は、定義されている場所に移動することができます。

その他の使用できるコマンドについては、ここ を参照して下さい。利用する言語サーバーによっては対応していないコマンドがあるようです。solargraph の場合、LspDeclarationLspPeekDecalation は対応していないようでした。

まとめ

solargraph と vim-lsp を使って、neovim で、LSP を利用しての ruby のコード補完や定義への移動ができるように設定をしてみました。vim でも バージョン8なら、同じように設定できるようです。

当初は、RubyMine で LSP を利用するように設定をしてみたかったのですが、試してみたところ、ruby に関しては、RubyMine のコード支援機能が協力強力で、変化がなかったため、neovim で設定をしました。

明日、Misoca+弥生 Advent Calendar 2019の3日目は、ryotaro_kawakami さんです。

AWS Lambda を Elixir で実行してみる

先日、AWS re:Invent 2018 で AWS Lambda にて Custom Runtime という機能が発表されました。興味があったので「New for AWS Lambda – Use Any Programming Language and Share Common Components | AWS News Blog」を読んでいると We are also working with our partners to provide more runtimes: Erlang (Alert Logic) Elixir (Alert Logic) という記述があり、Elixir好きとして試してみることにしました。

ビルド用コンテナイメージの作成

まずはじめに Elixir コードをコンパイルするための Docker コンテナイメージをビルドします。Elixir で書いたコードを AWS Lambda 上で実行するには、実行する同じ環境でコードをコンパイルする必要があるようです。以下のように GitHub から取得してビルドします。

$ git clone https://github.com/alertlogic/erllambda_docker.git
$ docker build -t erllambda:20.3-elixir erllambda_docker/elixir

プロジェクトの作成

コンテナを作成している間に Elixir プロジェクトを作成します。作成には、ローカル環境で Elixir が必要になります。

$ mix new hello_lambda
$ cd hello_lambda

lib/hello_lambda.ex を以下のように変更します。

defmodule HelloLambda do
  def handle(_event, _context) do
    {:ok, "Hello from Elixir"}
  end
end

ファンクション名はhandleとする必要があります。 mix.exsを編集してLambdaにアップロードするためのZIPファイルを作成するための依存性を追加します。

defp deps do
  [
    {:erllambda, "~> 2.0"},
    {:mix_erllambda, "~> 1.0"}
  ]
end

アップロードパッケージの作成

作成したコンテナを利用して以下のようにアップロードパッケージを作成します。

$ docker run -it --rm -v `pwd`:/buildroot -w /buildroot -e MIX_ENV=prod erllambda:20.3-elixir mix do deps.get, deps.compile, release.init, erllambda.release

本来なら release.init の後で rel/config.exs を確認すると良いのですが、今回は必要ないので一気にパッケージを作成します。 ビルドが成功すると _build/prod/rel/hello_lambda/releases/0.1.0/ 内に hello_lambda.zip が作成されているはずです。

Lambda 関数の作成

AWS コンソールにログインして Lambda 関数を作成します。ランタイムに「関数コードまたはレイヤーでカスタムランタイムを使用」を選択します。ロールは関数が実行できれば良いです。f:id:eitoball:20181219003705p:plain 関数が作成できたら作成したZIPファイルをアップロードします。アップロードする際は、ハンドラを「Elixir.HelloLambda」と指定して下さい。"HelloLambda"はプロジェクトでhandle関数があるモジュール名です。f:id:eitoball:20181219004141p:plain

関数の実行

テストイベントを作成して関数を実行します。テストイベントは「Hello World」というテンプレートを利用して下さい。実行が成功するとこのようにログに表示されます。 f:id:eitoball:20181219004440p:plain デフォルトの設定のメモリが128MBでタイムアウトが3秒する場合があるので、失敗する場合はログを見ながら適宜変更してみて下さい。

感想

AWS Lambda の関数をElixir などの色々な言語で書くことができるようになり選択が広がるのは良いことだと思いました。JavaScriptPython での場合と比べると起動が遅いような気がします。何か Elixir だと良い Lambda 関数とかがあるのだろうか…

 

 

 

Safecast Hackathon 2018 に参加してきました


id:eitoball です。この記事は Misoca+弥生 Advent Calendar 2018 5日目の記事です。
 
最近、Pixel 3 を手に入れてました。それを機に今更ながら、ポケモンGo を再開しました。表示言語を英語にしているのでポケモンを捕まえるたびに名前を見て何とも言えないもやもやが生じてしまうこの頃です。
 
先日、2018年11月30日から12月02日まで、Safecast Hackathon 2018 に参加してきました。簡単にレポートしたいと思います。 

Safecast とは

f:id:eitoball:20181205103001p:plain

Safecast は、2011年に起こった福島原子力発電所の事故による放射能漏れによる影響を
MITメディアラボ Joi Ito さん、起業家をしている Sean Bonnerさん、 Pieter Frankenさんを中心に発足したプロジェクトです。現在は、放射線量測定だけでなくPM2.5など色々な環境に関する測定してそのデータを広く公開するような活動をしています。
 
設立までのいきさつは、Joi Ito (伊藤穣一)さんの「9プリンシプルズ」の「プッシュよりプル」に書かれています。

Safecast に参加したきっかけ

2016年頃にプロジェクトに参加している Mat Schaffer さんが Ruby 東海でこのプロジェクトを紹介してくれて、測定データを集める API サーバーが Rails on Rails 製ということを聞いて、ローカル環境で動かす事ができるようにいくつかのパッチを送ったのがきっかけでした。それ以来、細々とボランティアとして、活動しています。

Hackathon

会場は、渋谷の Safecast のオフィスでした。今回は日本各地、アメリカ、オランダ、韓国などから20人ほど集まりました。API、可視化、ハードウェア、ウェブの4チームに分かれて作業をすることになりました。僕が参加した API チームでは福島やロサンゼルスなどに設置されている測定器から集まる放射線量やPM2.5といったデータを研究者が簡単に利用できるためのページを作成するということになりました。
 

f:id:eitoball:20181201095137j:plain

 
ハッカソンという名目ですが週末に集中して何かを作り上げるというよりは、各地からみんな集まって顔を合わせるという側面が強いイベントでした。コードを書くこともありましたが、ディスカッションをしながら、今後の方針を共有していく時間に多くを使っていました。 

最後に

久しぶりに英語だけで過ごす環境でした。最初は、人の話は聞いていて、言葉ははいってくるけど、理解が追いついてこないので、苦労しました。最終日の3日目あたりで追いつくようになりました。定期的に運動をして筋肉を維持するように定期的に英語だけで過ごして脳の回路を維持するようにする必要があるなぁと感じました。
 
明日の第6日目は、hasegawan さんが、「tracWiki文法の表を書きやすくExcel VBAアプリケーションを作った話」の予定です。面白そうです。

Ruby東海 第48回勉強会

10月30日にRuby東海の第48回勉強会をエイチーム様の会議スペース(ルーセントタワー32階)をお借りして開催しました。参加者は8名で、初めての方がいなかったので、まったりとした勉強会でした。

 

  • Vagrantを勉強しようとしている方がいたので、Ottoを勧めてみました。僕自身、Ottoが発表されたときに記事を斜め読みしたぐらいの知識しか無かったのですが、今から勉強するならと思って勧めてみました。近いうちに動かしてみてもう少し理解を深めようと思います。
  • Jupyter(旧、iPython)の多言語対応って、すごいねという話しを少ししました。現在、Rubyを含めて、50言語ほど対応しているようです。Railsコンソールとして使うことができると面白そう。
  • Coderetrietを名古屋でやろう!という話に何故かなりました。3年半ほど前に開催されて以来、開催されていないようです。是非、参加したいです。

 

相変わらず、Rubyについて、ほとんど話すことのない本編でした。懇親会は、いつものルーセントタワー地下1階にある名古屋丸八食堂でした。

 

  • NetflixHuluなどの動画サービスについての話をしました。僕は、最近、Huluで毎晩、ガンダム00を1話ずつ観ています。特にガンダムが好きとかいうわけではないですが、とりあえず、観ています。Netflixでは暖炉の動画が大人気らしいです。「ぱちぱち」と燃える音を聞きながら観ていると何となく心が和みます。YouTubeにも暖炉の動画が結構あがっているようです。
  • 技術的負債を返済していきたいなぁという話をしました。返済していかないとモチベーションが下がっていくのでやりたい。だけど、理解を得ることができないので、返済する作業ができないという悪い循環にはまってしまっているようです。どこかで悪い循環を断ち切るきっかけを探すことができるといいですが、結論は出ませんでした。

 

懇親会でもRubyについてほとんど話していないので、もう少しRuby関連の話をしないとなぁと反省しています。

 

次回、第49回勉強会は、11月27日に開催する予定です。決定しましたら、Doorkeeper経由にて告知します。よろしくお願いします。