ruby-lsp に貢献しよう

# はじめに

最近、Rubyの開発環境において、多くの開発チームやプロジェクトで、VSCode から RubyMine への移行が進んでいる。

https://github.com/Shopify/ruby-lsp

RubyMine は JetBrains 独自のコード解析機能を提供し、現時点では確かに ruby-lspより優れているように感じる。言語に依らず開発者が好きなエディタで開発できるのが、本来あるべき LSP を用いた開発環境の姿であるが、複数の言語を扱うプロジェクトにおいて、開発環境の分断化がされがちである。
- JavaScript や TypeScript ならば VSCode
- Ruby の開発には RubyMine
- Go の開発には VSCode / GoLand


OSSとしてのRuby LSPの発展には、実際の開発現場からのフィードバックや貢献が必要である。なので、その第一歩として、単純に「使ってみる」ことから貢献しませんか？

本章では、使い方、どんな機能があるか、貢献の仕方、について紹介する。

# 使ってみよう

**bundle install**
```ruby
# Gemfile
source "https://rubygems.org"

group :development do
  gem "ruby-lsp", require: false
  gem "rubocop", require: false
end
```
**VScodeの設定**
拡張をインストール
 
https://marketplace.visualstudio.com/items?itemName=Shopify.ruby-lsp
	
**その他エディタへの導入**
[参照](https://shopify.github.io/ruby-lsp/editors.html)

**既存プロジェクトで最新バージョンを試す**
1. プロジェクトの一つ上の階層に独自のワークスペースを作成する
1. 独自でワークスペース(`lsp.code-workspace`)を作り、`"rubyLsp.bundleGemfile":`など必要な設定があれば追加
1. ワークスペースから既存プロジェクトを開く

```shell
# イメージ
workspace/
  ├── Gemfile            # ruby-lspの最新バージョンを指定
  ├── workspace.code-workspace # パスの調整が必要な場合は、必要に応じで作成
  └── your-project/      # 既存のプロジェクト
      ├── Gemfile
      └── ...
```


# どんな機能がある
基本は直感的に利用できる、よく使う代表例3つ紹介
### 1. 参照箇所検索
VScodeのサイドバーに参照箇所一覧が表示される。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557072/1be808e5-2014-8681-da00-d6aec266c104.png)

```ruby
class User
    attr_reader :name
    def initialize(name:)
        @name = name
    end
   
    def greeting # 👈 右クリック `find all reference`で参照箇所一覧を表示
        "Hello, #{name}!"
    end
end
```

:::note warn
 現状、全てのクラスの`greeting`を検索してしまう課題はある。
:::

### 2. 定義ジャンプ
command + clickで定義元へジャンプする
```ruby
user = User.new(name: 'Ruby')
user.greeting # 👈 Userのgreetingへジャンプ

admin = Admin.new(name: 'Kotlin')
admin.greeting # 👈 Adminのgreetingへジャンプ
```
### 3. 型推論
インスタンス名からクラスを推論し、インスタンスが持つメソッドを提案する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557072/883a40dd-5158-c258-ff4d-9b96370ffe9e.png)

```ruby
# `user` が Userクラスのインスタンスであることを推論する
user = User.new(name: 'Ruby')
user.gre # Userクラスが持つメソッドを提案 `greeting`

# 変数`k` は Userクラスのインスタンスであることを推論しない
k = User.new(name: 'Kotlin')
k.gre # クラスが持つメソッドを提案しない

user = Admin.new(name: 'Ruby')
# ⚠️ Userインスタンスと推論するので、Adminで定義していてもUserのgreetingにジャンプ
user.greeting
```

:::note warn
推論ミスで関係ない型を提案したり、意図しない定義ジャンプすることもある。
`User` クラスが既に定義されている場合、別箇所で`user`を呼ぶと暗黙的に`user`は `User`インスタンスと識別する。
:::


その他にもいろんな機能が搭載されている

https://shopify.github.io/ruby-lsp/#folding-range

### 機能の課題
- [ ] 推論に依存した機能が多い
    - 変数名などの命名規則にこだわる必要がある
- [ ] 推論でなく型を明記できる方法として、RBSを検討しているらしい
    - [solargraph のようにYardに対応する予定はない](https://github.com/Shopify/ruby-lsp/issues/2181)
- [ ] [AddOn連携と、Rails AddOnの開発に注力しているそう](https://shopify.github.io/ruby-lsp/rails-add-on.html)
    - 開発者が独自でruby-lspをカスタムすることができるようになる
- 欲しい機能 🥺
    - YardのAddOn?
    - AST関係ないが、文字パターンを解析して、特定ファイルにジャンプ




# 貢献してみる
[環境構築方法](https://shopify.github.io/ruby-lsp/contributing.html#initial-setup)
### 開発環境のセットアップ

1.  クローンしてVSCodeを開く
    ```shell
    git clone https://github.com/Shopify/ruby-lsp.git
    code ruby-lsp    
    ```
1. 依存ツールインストール
    ```shell
    # root
    bundle install

    # cd vscode
    yarn install
    ```
    
### 開発の方法
:::note
 ruby-lspでは、大きくvscode拡張機能とlsp開発があり、それぞれデバッグ方法は異なる
:::


**LSP 開発** 
1. ワークスペース`/lsp.code-workspace` を開く
1. 検証用プロジェクト サーバー起動、CMD/CTRL + SHIFT + P → 入力 「`Debug the Ruby LSP`」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557072/ff859f2b-197b-9156-bc0a-44eeeb5f1623.png)

1. ruby-lsp Vscode `Run/Debug` → 「`attach to existing server`」
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557072/4daecac4-a3e0-0e7a-568f-3c51efdf3d29.png)
1. 既存のプロジェクトを用いて検証できる状態になる
1. 検証して、開発！

    ```mermaid
    graph LR
        dev["デバッグLSP<br>(ローカルポート)"] 
        vscode["VS Code<br>既存(検証用)プロジェクト"]
        vscode <-->|"接続して検証"| dev
    ```

**VSCode拡張の開発**
1. ワークスペース`/lsp.code-workspace` を開く
1. ruby-lsp Vscode `Run/Debug` → 「`Run Extension`」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/557072/b850e806-5c62-c0df-6237-51a8d4376ba6.png)
1. 拡張デバッグ用のエディタが開くので、任意の検証用プロジェクトを開く
1. 検証して、開発！
    ```mermaid
    graph LR
    subgraph "任意のLSP"
        local["開発中LSP"]
        version["既にある任意バージョンLSP"]
    end

    vscode["VSCode<br/>デバッグモード"]

    local --> |"連携"| vscode
    version --> |"連携"| vscode
    ```

:::note
テストスクリプトの書き方は[公式ドキュメントを参考](https://shopify.github.io/ruby-lsp/contributing.html#initial-setup)
:::



**LSPのリクエスト周りの定義を理解する**
LSPの用語や説明をまとめたドキュメント

https://github.com/tennashi/lsp_spec_ja

**課題を見つける**
- １００近く課題があり、今時点で毎日のペースで消化されており、日々進化している！

https://github.com/Shopify/ruby-lsp/issues


- PRやコミット方法に厳格なルールはないので気軽に参加できる
コミット例(私の)

https://github.com/Shopify/ruby-lsp/pull/2719


# 最後に
商用ツールに頼らずもっとOSSとしていいものをいろんな人が快適にRubyを使えるようになればいいなと思う。
MCPよりLSP!