Slide 1

Slide 1 text

1 Shoki Hata 2024/06/08 GoのLanguage Server Protocol実装、 「gopls」の自動補完の仕組みを学ぶ Go Conference 2024

Slide 2

Slide 2 text

2 2 software engineer at Kanmu, Inc. 畠 翔紀 / Shoki Hata GitHub @sho-hata X @sho_hata_ 自己紹介

Slide 3

Slide 3 text

3 3 カンムはGo Conference 2024 ブロンズスポンサーとして協賛します 誰でもすぐに作って買い物できる Visaプリカアプリ 手元の資産形成に活用できるクレジットカード

Slide 4

Slide 4 text

4 4 丸腰のエディタでGoのコードを書いている人は いますか? ※丸腰...補完機能などの支援が一切ない状態

Slide 5

Slide 5 text

5 5 今日話すこと Goでのコーディング...を支える裏側の話

Slide 6

Slide 6 text

6 6 ● 補完機能ってどうやって動いているの? ○ 入力途中だとコンパイルできないはずなのに、ほぼリアルタイ ムで提案してくれる 気になりませんか?

Slide 7

Slide 7 text

7 7 ● どのようにして補完情報を集めているの? ○ まさか全てのリポジトリから補完候補を集めていることはないは ず... ○ 集めてくるルールや優先順みたいなのはあるのか 気になりませんか?

Slide 8

Slide 8 text

8 8 Goのコーディング支援機能を提供する goplsの自動補完の仕組み ● 今日のゴール ○ goplsの補完機能の流れを把握する ○ Goのエコシステムに興味を持ってもらう 今日話すこと

Slide 9

Slide 9 text

9 9 目次 Language Server Protocolとは goplsの概要 goplsの自動補完機能の仕組み を探検する INDEX 1 2 3

Slide 10

Slide 10 text

10 Language Server Protocolとは

Slide 11

Slide 11 text

11 11 Language Server Protocol(LSP)とは エラー報告 定義ジャンプ シンボルの説明

Slide 12

Slide 12 text

12 定義ジャンプ、入力補完、参照の取得... → Language Server Protocolによって支えられている

Slide 13

Slide 13 text

13 13 エラーチェックやコードの補完などの機能を、いろんなエディタや 統合開発環境(IDE)が共通の方法で利用できるようにするための規格 Language Server Protocol(LSP)とは Copyright © 2024 JetBrains s.r.o. [JETBRAINS PRODUCT NAME - e.g Rider ] and the [Rider] logo are registered trademarks of JetBrains s.r.o.

Slide 14

Slide 14 text

14 14 Language Server Protocol(LSP)とは VSCode公式より PHP

Slide 15

Slide 15 text

15 goplsの概要

Slide 16

Slide 16 text

16 16 Go Language Server Go Language Client Language Server Protocol JSON RPC gopls PHP gopls is Language Server for Golang

Slide 17

Slide 17 text

17 17 goplsが目標としていること ● Goエンジニアが使用する主要なエディターの デフォルトバックエンドとなること ● LSPの機能を可能な限り実装、標準化すること ● 省メモリ・低レイテンシーで動かすこと

Slide 18

Slide 18 text

18 18 gopls以前 VSCode vim etc... Go 拡張機能 gopkgs go-outline go-simples guru gorename gomodifytags goplay godef gotype-live gocode gogetdoc goimports goreturns gofmt golint impl gometalinter staticcheck golangci-lint revive fillstruct dlv godoctor gotests

Slide 19

Slide 19 text

19 19 gopls以後 VSCode vim etc... Go 拡張機能 gopkgs go-outline go-simples guru gorename gomodifytags goplay godef gotype-live gocode gogetdoc goimports goreturns gofmt golint impl gometalinter staticcheck golangci-lint revive fillstruct dlv godoctor gotests gopls

Slide 20

Slide 20 text

20 20 便利な機能、自動補完

Slide 21

Slide 21 text

21 21 ● 補完機能ってどうやって動いているの? ● どのようにして補完情報を集めているの? 使っていて気になりませんか?

Slide 22

Slide 22 text

22 goplsの自動補完機能の仕組みを探検する

Slide 23

Slide 23 text

23 23 A:コンパイルしていない。 ソースコードを元に補完対象を探している。 Q:入力途中の状態ってコンパイルできないけど、 どうなってるの?

Slide 24

Slide 24 text

24 24 go/pkg completion カーソルの位置情報 補完結果 ソースコード 使用パッケージを go install バイナリ gopls以前(gocode)

Slide 25

Slide 25 text

25 25 go/pkg ビルドキャッシュ 最新 gocode 補完結果 補完結果 ズレがおこる gopls以前(gocode) ビルドキャッシュの到来

Slide 26

Slide 26 text

26 26 cache カーソルの位置情報 構文木 カーソルの位置情報 補完結果 エディタ *.go go.mod タイミング: 初期化や都度ファイル変更など snapshot completion gopls gopls

Slide 27

Slide 27 text

27 27 どのようにして補完情報を集めているの?

Slide 28

Slide 28 text

28 28 文脈に応じたルールベースでの単語の補完 GitHub Copilotとは方式が異なる

Slide 29

Slide 29 text

29 29 ケーススタディ 「fmt.Println」を記述しようとしている。 「P」を入力したときの補完の流れを少し覗いてみよう ※説明をシンプルにするため、か なり必要に応じて単純化したり、 処理を省いたりしています。 コード :gopls/internal/work/comple tion.go

Slide 30

Slide 30 text

30 30 cache ファイルuri, カーソルの位置情報 構文木 ファイルuri 補完結果 エディタ snapshot completion gopls ??? ここの流れを追っていきます

Slide 31

Slide 31 text

31 31 ● サーバー ○ リクエスト解析、処理振り分け ● 補完処理 ○ キャッシュからパッケージ情報の探索 ○ カーソル周辺の構文木解析 ○ 補完必要かどうか判断 ○ 補完候補の収集、スコア重みづけ ● サーバー ○ 補完結果をレスポンスとして返却 大まかな流れ

Slide 32

Slide 32 text

32 32 ● サーバー ○ リクエスト解析、処理振り分け ● 補完処理 ○ キャッシュからパッケージ情報の探索 ○ カーソル周辺の構文木解析 ○ 補完必要かどうか判断 ○ 補完候補の収集、スコア重みづけ ● サーバー ○ 補完結果をレスポンスとして返却 大まかな流れ

Slide 33

Slide 33 text

33 ファイルURI 行数、位置 リクエスト解析

Slide 34

Slide 34 text

34 34 ● サーバー ○ リクエスト解析、処理振り分け ● 補完処理 ○ キャッシュからパッケージ情報の探索 ○ カーソル周辺の構文木解析 ○ 補完必要かどうか判断 ○ 補完候補の収集、スコア重みづけ ● サーバー ○ 補完結果をレスポンスとして返却 大まかな流れ

Slide 35

Slide 35 text

35 35 キャッシュからそのファイルが属するパッケージ情報の探索 snapshot

Slide 36

Slide 36 text

36 36 キャッシュからそのファイルが属するパッケージ情報の探索 cache 構文木 ファイルuri: `file:///path/to/main.go` snapshot completion

Slide 37

Slide 37 text

37 37 カーソル周辺の構文木解析 カーソル位置からルートノードまでの ASTを調べて、 補完が有効な位置かどうかを判断する 関数呼び出しの中では補完しない リテラル内では補完しない 様々なチェックを乗り越える!

Slide 38

Slide 38 text

38 38 スコープ情報の収集 スコープの狭い順に集めていく 1. fmtパッケージ 2. mainパッケージ …

Slide 39

Slide 39 text

39 39 ● ★補完コンテキスト(スコープ)に マッチしているか ● プライベートオブジェクト 補完候補のスコア重みづけ スコアUP スコアDown ● メソッド呼び出し ● foo[0]のようなインデックス 修飾子 ソース:gopls/internal/golang/completion/deep_completion.go addCandidateメソッド

Slide 40

Slide 40 text

40 補完結果をレスポンスとして返却

Slide 41

Slide 41 text

41 41 まとめ ● 補完処理では、カーソル位置を元にキャッシュから構文木を取得・ 解析し、ルールに基づいて補完候補を算出している ● スマートに、かつ適切な候補を提案してくれる裏側では、 泥臭く堅実な処理が行われている

Slide 42

Slide 42 text

42 Thank you! ありがとうございました

Slide 43

Slide 43 text

43 参考情報 ● gopls Design Documetion ○ https://github.com/golang/tools/blob/master/gopls/doc/design/design.md ● gopls Architecture ○ https://github.com/golang/tools/blob/master/gopls/doc/design/implementation.md ● Scaling gopls for the growing Go ecosystem ○ https://go.dev/blog/gopls-scalability ● Language Server Protocol の仕様 及び実装方法 ○ https://zenn.dev/mtshiba/books/language_server_protocol ● gocode やめます(そして Language Server へ) ○ https://mattn.kaoriya.net/software/lang/go/20181217000056.htm