🫰

mruby用のLanguage ServerをGo言語で作ってみた💎

に公開

こんにちは!🤖

都内でエンジニアをしているhamachangです!

前回投稿した「Go言語でmrubyの静的型検査器を作ってみた💎」
https://zenn.dev/ehamachang/articles/f992aa6f0ca8c9

の続きとはなりますが、

今回は mruby用のLanguage ServerをGo言語で作ってみました✨

今回作ったやつ「ruby-ti-lsp」の紹介

「Ruby-TI」とは、自分が作成したmruby用の静的型検査器なんですが、
ruby-ti-lspはRuby-TIの型検査をエディタから利用するやつですね。

ソースコードはこんな感じになりました🗒️
https://github.com/engneer-hamachan/ruby-ti-lsp

スクリーンショットはこんな感じですね。

機能としては、

  • 型注釈(Code Lens)
  • 補完 (Completion)
  • メソッドジャンプ(Definition)
  • 型検査(Diagnostics)

を実装しています🔧

なぜ作ったのか🤔

RubyTI本体に同じ様な機能を持つVim拡張(VimScript製)を同梱してたのですが、あくまでVim専用となっていました。

やっぱ作ったからには色んな人に使って欲しい。。。

きっと流行ってないのはVSCodeで使えないからだ!

よしVSCode対応(Language Serverを実装)だ!

と言う短絡的な動機です☝

Go言語で簡単にLanguage Serverが実装出来る「glsp」の紹介

そしてGo言語でLanguage Serverを実装しようとして色々調べてたら、見つけちゃったんですね。素敵なライブラリ。

それが「glsp」です。
https://github.com/tliron/glsp

本当に上手いことLSPを抽象化してくれていて、
めちゃくちゃ実装しやすかったです。

多分Language Serverを実装するぞ!ってなってから、1週間前後くらいで実装したんですが、全部このglspのお陰ですね!

func textDocumentCompletion(
        ctx *glsp.Context,
        params *protocol.CompletionParams,
) (any, error) {

        var items []protocol.CompletionItem

        content, ok := documentContents[params.TextDocument.URI]
        if !ok {
                return nil, nil
        }

        signatures :=
                findComplection(content, params.Position.Line, params.Position.Character)

        for _, sig := range signatures {
                items =
                        append(items, protocol.CompletionItem{
                                Label:  sig.Method,
                                Detail: &sig.Detail,
                        })
        }

        return items, nil
}

これは、補完の実装になるのですが、
こんな感じのメソッドを作って、

func NewServer() *server.Server {
        handler = protocol.Handler{
                Initialize:             initialize,
                TextDocumentDidOpen:    textDocumentDidOpen,
                TextDocumentCompletion: textDocumentCompletion,
                TextDocumentDidChange:  textDocumentDidChange,
                TextDocumentDidSave:    textDocumentDidSave,
                TextDocumentDefinition: textDocumentDefinition,
                TextDocumentCodeLens:   textDocumentCodeLens,
        }

        server := server.NewServer(&handler, "ruby-ti", false)
        return server
}

こんな感じでhandlerに登録すると実装が終わって、

Language Serverで補完機能を提供する事ができます(超絶便利ですね!)

あとLSPの仕組みを理解する目的としても、個人的にはおすすめのライブラリで、
LSPの仕組みを知りたい!って方にも是非使ってみて欲しいです🪛

やっぱり実装してみると理解は深まりますし💡

そしてリリースへ📅

VSCodeに対応したと言う事で、早速ウキウキでruby-ti-lspをリリースしてみたのですが、

RubyTIが流行って無い理由とVSCode対応は全然関係が無かった

と言う所までは解りました🙆

RubyTIの今後🚀

やっぱり使ってくれる人を増やすには、普段の仕事でもある程度使えないと行けないのかなーとか、
LSPをリリースして感じたので、今はそんな事を考えながら実装を進めています。

もう少し具体的的な話だと、

Ruby-TIはmruby用途のものではありますが、

設定をちゃんとすればCRubyやRailsでも使おうと思えば使えるので、

PR的に「Railsで使用してみた!」とか出来たら、少し使ってみよう!ってなる人が増える気がしています💡
(ただmruby用途に拘りたい理由もあるので、引き続きmruby用として提供すると思います)

なので、そこに向けて設定を簡略化する機能を作ったり、ドキュメントの整備を進めて行くつもりです✌

まあ上手く行っても行かなくても、物を作るって本当に楽しいですよね!😎

そもそも現状の試行錯誤がもう楽しいです✨

話が少し逸れた気がしますが、

「glsp」

おすすめです⭐⭐⭐

Discussion