Gleam 言語サーバ リファレンス
原文: The Gleam language server reference ── © Louis Pilfold and the Gleam contributors, Apache-2.0。日本語訳 © 2026 Canonical。
Gleam 言語サーバは、VS Code や Neovim のような言語サーバプロトコルを実装したテキストエディタに IDE 機能を提供するプログラムです。この文書では、言語サーバの現状とその機能について詳しく説明します。
プロジェクトの状況
Gleam 言語サーバは、公式の Gleam プロジェクトの一環であり、Gleam ツールチェインの中で最も新しいコンポーネントです。活発に開発が進められ、急速に改善されていますが、歴史の長い言語における成熟した言語サーバほどすべての機能が揃っているわけではありません。
現在進行中の開発状況を確認したい場合は、Gleam のロードマップを参照してください。
インストール
Gleam 言語サーバは標準の gleam バイナリに同梱されています。そのため、Gleam をインストールしていれば言語サーバもすでにインストールされています。ただし、Gleam のコードに対して言語サーバを使用するには、エディタ側で設定が必要になる場合があります。
Gram
Gram は言語サーバを標準でサポートしています。追加の設定は必要なく、Gleam のファイルを開くと、Gram が自動的に言語サーバを起動します。
Helix
Helix は言語サーバを標準でサポートしています。追加の設定は必要なく、Gleam のファイルを開くと、Helix が自動的に言語サーバを起動します。
Neovim
Neovim の nvim-lspconfig には Gleam 向けの設定が含まれています。お好みのプラグインマネージャで nvim-lspconfig をインストールし、init.lua に言語サーバを追加してください。
Nvim 0.11 以降かつ nvim-lspconfig 2.1 以降の場合:
vim.lsp.enable('gleam')Nvim 0.10 以前の場合:
require('lspconfig').gleam.setup({})これにより、Gleam のファイルを開いた際に言語サーバが自動的に起動します。
nvim-treesitter を使用している場合は、:TSInstall gleam を実行することで、シンタックスハイライトをはじめとする tree-sitter の機能を利用できます。
VS Code
VS Code Gleam プラグインをインストールしてください。
これにより、Gleam のファイルを開いた際に言語サーバが自動的に起動します。もし VS Code が言語サーバを実行できない場合は、gleam バイナリが VS Code の PATH に含まれているかを確認し、VS Code の再起動をお試しください。
Zed
Gleam のファイルを開くと、Zed が Gleam プラグインのインストールを提案します。インストール後は、Gleam のファイルを開くと言語サーバが自動的に起動するようになります。
その他のエディタ
言語サーバプロトコルに対応しているエディタであれば、どれでも Gleam 言語サーバを利用できます。ワークスペースのルートディレクトリで gleam lsp を実行するようにエディタを設定してください。
機能
複数プロジェクトの対応
1 つのエディタセッションで複数のプロジェクトの Gleam ファイルを開くことができます。Gleam 言語サーバは、それぞれのファイルがどのプロジェクトに属しているか、また各プロジェクトをどのように処理すべきかを理解します。
プロジェクトのコンパイル
言語サーバは、エディタで開かれている Gleam プロジェクトのコードを自動的にコンパイルします。ただし、コード生成と Erlang のコンパイルは行いません。
エディタで編集中の未保存ファイルがある場合、言語サーバはその編集内容を反映してコンパイルを行います。
コンパイルには gleam.toml で指定されたターゲットが使用されます。ターゲットが指定されていない場合の既定値は Erlang です。
エラーと警告の診断
Gleam コードのコンパイル時に検出されたエラーや警告は、言語サーバの診断結果としてエディタ上に表示されます。
コードの整形
言語サーバは Gleam フォーマッタを使用してコードを整形できます。ファイル保存時に自動で整形が実行されるよう設定しておくことをおすすめします。
ホバー
言語サーバは、以下の要素にホバーした際にドキュメント、型、その他の情報を表示します。
- 定数。
- import 文(非修飾の値と型を含む)。
- モジュールの関数。
- モジュール修飾子。
- パターン。
- レコードのフィールド。
- レコードパターンで残りのフィールドを無視するための
..。 - 型注釈。
- 値。
定義へ移動
言語サーバは、以下の要素について定義元への移動をサポートしています。
- 定数。
- カスタム型のバリアント。
- 関数。
- import 文(非修飾の値と型を含む)。
- モジュール。
- レコードのフィールド。
- 型注釈。
- 変数。
型定義へ移動
言語サーバは、型定義への移動に対応しています。式の上で実行すると、その式で使用されているすべての値の型を特定し、それぞれの定義を提示して閲覧や移動ができるようにします。
参照の検索
言語サーバは、以下の要素について参照の検索をサポートしています。
- 定数。
- カスタム型のバリアント。
- 関数の引数。
- 関数。
- レコードのフィールド。
- 型。
- 変数。
コード補完
言語サーバは、以下の補完に対応しています。
- 関数の引数。
- 他のモジュールで定義された関数と定数。そのモジュールが未 import の場合は、自動的に import 文を追加します。
- 同じモジュール内で定義された関数と定数。
- ローカルに定義された変数。
- import 文内のモジュール。
- レコードのフィールド。
- 型注釈内の型コンストラクタ。
- import 文内の非修飾の型と値。
名前の変更
言語サーバは、以下の名前を変更できます。
- 定数。
- カスタム型のバリアント。
- 関数の引数。
- 関数。
- import したモジュールの別名。
- レコードのフィールドラベル。
- 型パラメータ。
- 型。
- 変数。
ドキュメントシンボル
言語サーバは、現在の Gleam ファイル内にある関数や定数などのドキュメントシンボルの一覧表示に対応しています。
シグネチャヘルプ
言語サーバは、関数を呼び出す際に各引数の型を表示できます。引数にラベルがある場合は、ラベルも併せて表示します。
コードの折りたたみ
言語サーバは、連続する import 文のまとまりや、関数本体、カスタム型、定数、型エイリアスなどの複数行にわたるトップレベルの定義について、折りたたみ可能な範囲をエディタに通知します。
コードアクション
無名関数ラッパの追加と削除(Add and remove anonymous function wrappers)
このコードアクションでは、関数への参照と、その関数を呼び出す無名関数とを相互に変換できます。これら 2 つの構文は等価です。
pub fn main() {
fn(a, b) { int.add(a, b) }
}別の関数を直接呼び出している無名関数内にカーソルを合わせると、「無名関数ラッパの削除」のコードアクションが提案されます。実行すると、コードは次のように更新されます。
pub fn increment(x: Int) -> Int {
int.add
}int.add のような関数参照の中にカーソルを合わせると、「無名関数で包む」のコードアクションが提案され、実行するとコードは元の状態に戻ります。
型注釈の追加(Add annotations)
このコードアクションは、代入や関数に型注釈を追加できます。
pub fn increment(x) {
x + 1
}引数や戻り値の型がすべては注釈されていない関数内にカーソルを合わせると、コードアクションが提案されます。実行すると、型注釈を含むようにコードが更新されます。
pub fn increment(x: Int) -> Int {
x + 1
}このコードアクションは、let や use による代入に対しても実行できます。
欠けている import の追加(Add missing import)
このコードアクションは、不足している import 文を追加できます。
pub fn main() -> Nil {
io.println("Hello, world!")
}io.println の中にカーソルがあり、io という名前で import 可能なモジュールに println という関数が存在する場合に、コードアクションが提案されます。実行すると、コードは次のように更新されます。
import gleam/io
pub fn main() -> Nil {
io.println("Hello, world!")
}欠けているパターンの追加(Add missing patterns)
このコードアクションは、網羅的でない case 式に対して不足しているパターンを追加できます。
pub fn run(value: Bool) -> Nil {
case value {}
}case 式の中にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub fn run(value: Bool) -> Nil {
case value {
True -> todo
False -> todo
}
}欠けている型パラメータの追加(Add missing type parameter)
このコードアクションは、カスタム型の定義に不足している型パラメータを追加できます。
pub type Store {
Store(name: String, data: inner_type)
}このコードは inner_type がスコープに存在しないためコンパイルできません。
定義内にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub type Store(inner_type) {
Store(name: String, data: inner_type)
}省略されたラベルの追加(Add omitted labels)
このコードアクションは、関数やレコードコンストラクタの呼び出しにおいて省略されたラベルを追加できます。
pub type User {
User(first_name: String, last_name: String, likes: List(String))
}
pub fn main() {
let first_name = "Giacomo"
User(first_name, "Cavalieri", ["gleam"])
}すべてのラベルが指定されていない呼び出し内にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub type User {
User(first_name: String, last_name: String, likes: List(String))
}
pub fn main() {
let first_name = "Giacomo"
User(first_name:, last_name: "Cavalieri", likes: ["gleam"])
}命名のケース修正(Case correction)
このコードアクションは、誤った大文字・小文字の使い分け(ケース)で書かれた名前を修正できます。
pub main() {
let myNumber = 100
}誤ったケースで命名された識別子にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub main() {
let my_number = 100
}入れ子の case 式の畳み込み(Collapse nested case expressions)
このコードアクションは、ある節の本体が別の case 式になっており、かつその case 式が親の節のパターンで束縛された変数にマッチしている場合に、2 つの case 式を 1 つにまとめます。
pub fn main() {
case user {
User(name:) ->
case name {
"Joe" -> "Hello, Joe!"
_ -> "Hello there!"
}
Guest -> "You're not logged in!"
}
}入れ子になった case 式の中にカーソルを合わせるとコードアクションが提案され、実行するとモジュールは次のように更新されます。
pub fn main() {
case user {
User(name: "Joe") -> "Hello, Joe!"
User(name: _) -> "Hello there!"
Guest -> "You're not logged in!"
}
}コメントの変換(Convert comment)
このコードアクションは、通常のコメントとドキュメントコメントを相互に変換できます。
// This is my favourite function.
pub fn wibble() {
123
}コメント内にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
/// This is my favourite function.
pub fn wibble() {
123
}このコードアクションを利用して、ドキュメントコメントを通常のコメントに戻すこともできます。また、モジュールの先頭にあるコメントをモジュールのドキュメントコメントに変換することも可能です。
int の基数変換(Convert int base)
これらのコードアクションは、int リテラルを 10 進数、8 進数、16 進数、2 進数の間で変換します。
pub fn lucky_number() {
0b1011
}int リテラル内にカーソルを合わせるとコードアクションが提案されます。10 進数への変換を実行すると、コードは次のように更新されます。
pub fn lucky_number() {
11
}パイプとの相互変換(Convert to and from pipe)
これらのコードアクションは、|> を用いたパイプ構文と通常の関数呼び出し構文とを相互に変換します。
import gleam/list
pub fn main() {
list.map([1, 2, 3], double)
}リストの引数内にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
import gleam/list
pub fn main() {
[1, 2, 3] |> list.map(double)
}もう一度コードアクションを実行すると、元の状態に戻ります。
最初の引数以外をパイプしたい場合は、コードアクションを実行する前にエディタ上で対象の引数を選択してください。
use との相互変換(Convert to and from use)
これらのコードアクションは、use 構文と通常の関数呼び出し構文とを相互に変換します。
pub fn main() {
use profile <- result.try(fetch_profile(user))
render_welcome(user, profile)
}use 式の中にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub fn main() {
result.try(fetch_profile(user), fn(profile) {
render_welcome(user, profile)
})
}もう一度コードアクションを実行すると、元の状態に戻ります。
未知のモジュールの作成(Create unknown module)
このコードアクションは、import されているものの存在しないモジュールに対して、空の新しいモジュールを作成します。
import wibble/wobbleこのコードにおいて wibble/wobble という名前のモジュールが存在しない場合、import 文からコードアクションが提案されます。実行すると、同じパッケージ内に新しいモジュールが作成されます。
未使用の Result の破棄(Discard unused result)
このコードアクションは、使用されていない Result を _ に代入して警告を抑制します。通常は、起こりうるエラーを単に無視するよりも、Result を適切に処理する方が望ましいです。
pub fn main() {
function_which_can_fail()
io.println("Done!")
}Result を返す文の中にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub fn main() {
let _ = function_which_can_fail()
io.println("Done!")
}関数キャプチャの展開(Expand function capture)
このコードアクションは、関数キャプチャ構文を無名関数に変換します。
pub fn main() {
let add_eleven = int.add(_, 11)
list.map([1, 2, 3], add_eleven)
}関数キャプチャ内にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub fn main() {
list.map([1, 2, 3], fn(value) { int.add(value, 11) })
}定数の抽出(Extract constant)
このコードアクションは、式を定数として抽出します。
const first = "Hello, Mike!"
pub fn main() {
list.each([first, "Hello, Joe!"], io.println)
}リスト内にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
const first = "Hello, Mike!"
const values = [first, "Hello, Joe!"]
pub fn main() {
list.each(values, io.println)
}変数の抽出(Extract variable)
このコードアクションは、式を変数として抽出します。
pub fn main() {
list.each(["Hello, Mike!", "Hello, Joe!"], io.println)
}リスト内にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub fn main() {
let value = ["Hello, Mike!", "Hello, Joe!"]
list.each(value, io.println)
}ラベルの穴埋め(Fill labels)
このコードアクションは、呼び出し時に期待されるラベルを追加します。
pub fn main() {
Date()
}Date() の中にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub fn main() {
Date(year: todo, month: todo, day: todo)
}使われていないフィールドの穴埋め(Fill unused fields)
このコードアクションは、パターンマッチで明記されていないフィールドを追加します。
pub type Pokemon {
Pokemon(id: Int, name: String, moves: List(String))
}
pub fn main() {
let Pokemon(..) = todo
}.. の中にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub type Pokemon {
Pokemon(id: Int, name: String, moves: List(String))
}
pub fn main() {
let Pokemon(id:, name:, moves:) = todo
}デコーダの生成(Generate decoder)
このコードアクションは、カスタム型の定義から dynamic デコーダ関数を生成します。
pub type Person {
Person(name: String, age: Int)
}「Person」という型名の中にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
import gleam/dynamic/decode
pub type Person {
Person(name: String, age: Int)
}
fn person_decoder() -> decode.Decoder(Person) {
use name <- decode.field("name", decode.string)
use age <- decode.field("age", decode.int)
decode.success(Person(name:, age:))
}関数の生成(Generate function)
このコードアクションは、使用されているもののまだ存在しないローカル関数の定義を生成します。
pub fn main() {
let items = [1, 2, 3]
io.println(describe(items))
}describe の中にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
import gleam/io
pub fn main() {
let items = [1, 2, 3]
io.println(describe(items))
}
fn describe(list: List(Int) -> String {
todo
}JSON 変換関数の生成(Generate to-JSON function)
このコードアクションは、カスタム型の値を gleam_json ライブラリを使用して JSON に変換する関数を生成します。
pub type Person {
Person(name: String, age: Int)
}pub type Person { の定義内にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
import gleam/json
pub type Person {
Person(name: String, age: Int)
}
fn person_to_json(person: Person) -> json.Json {
let Person(name:, age:) = person
json.object([
#("name", json.string(person.name)),
#("age", json.int(person.age)),
])
}型の生成(Generate type)
このコードアクションは、使用されているもののまだ存在しない型の定義を生成します。
pub fn run(data: Wibble(Int)) {
todo
}Wibble の中にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub type Wibble(a)
pub fn run(data: Wibble(Int)) {
todo
}非網羅的な let から case へ(Inexhaustive let to case)
このコードアクションは、パターンが網羅的でない場合に let を case に変換します。
pub fn unwrap_result(result: Result(a, b)) -> a {
let Ok(inner) = result // error: inexhaustive
inner
}let による代入の中にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub fn unwrap_result(result: Result(a, b)) -> a {
let inner = case result {
Ok(inner) -> inner
Error(_) -> todo
}
inner
}変数のインライン化(Inline variable)
このコードアクションは、1 度しか使用されていない変数をインライン化します。
pub fn main() {
let greeting = "Hello!"
echo greeting
}変数 greeting の中にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub fn main() {
echo "Hello!"
}文字列の補間(Interpolate string)
このコードアクションは、値を補間するために文字列を分割します。
pub fn greet(name: String) -> String {
"Hello, !"
}文字列内の ! の直前にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
pub fn greet(name: String) -> String {
"Hello, " <> todo <> "!"
}カーソルが Gleam の名前として妥当な範囲を選択している場合は、それが補間される変数名として使用されます。
pub fn greet(name: String) -> String {
"Hello, name!"
// ^^^^ This is selected
}pub fn greet(name: String) -> String {
"Hello, " <> name <> "!"
}パターンマッチ(Pattern match)
このコードアクションは、変数や引数に対する網羅的な case 式を生成します。
import gleam/list
pub fn run(items: List(Int)) -> Nil {
let result = list.first(items)
}result への代入内にカーソルを合わせるとコードアクションが提案され、実行するとコードは次のように更新されます。
import gleam/list
pub fn run(items: List(Int)) -> Nil {
let result = list.first(items)
case result {
Ok(value) -> todo
Error(value) -> todo
}
}このコードアクションは関数呼び出しに対しても実行でき、その呼び出しの戻り値をパターンマッチできます。
修飾と非修飾(Qualify and unqualify)
これらのコードアクションは、型や値のモジュール修飾子を追加または削除します。
import gleam/option.{Some}
pub fn main() {
[Some(1), Some(2)]
}いずれかの Some の中にカーソルを合わせると「修飾」のコードアクションが提案され、実行するとコードは次のように更新されます。
import gleam/option.{}
pub fn main() {
[option.Some(1), option.Some(2)]
}必要に応じて import 文が更新され、モジュール内のすべての Some コンストラクタが修飾されている点に注目してください。
「非修飾」のアクションも同様に機能しますが、こちらはモジュール修飾子を削除します。
「非修飾」のアクションは型とカスタム型のバリアントコンストラクタに対して使用でき、「修飾」のアクションはすべての型と値に対して使用できます。
ブロックの削除(Remove block)
このコードアクションは、単一の式を囲んでいるブロックを削除します。
pub fn greet(name: String) {
case name {
"Joe" -> { "Hello, Joe!" }
_ -> "Hi " <> name
}
}"Hello, Joe!" という文字列を含むブロックの中にカーソルを合わせるとコードアクションが提案され、実行するとモジュールは次のように更新されます。
pub fn greet(name: String) {
case name {
"Joe" -> "Hello, Joe!"
_ -> "Hi " <> name
}
}echo の削除(Remove echo)
このコードアクションは echo 式を削除します。デバッグが完了したあとに便利です。
pub fn main() {
echo 1 + 2
}echo の中にカーソルを合わせるとコードアクションが提案され、実行するとモジュールは次のように更新されます。
pub fn main() {
1 + 2
}モジュール内に複数の echo 式がある場合は、すべて削除されます。
非公開型からの opaque の削除(Remove opaque from private type)
このコードアクションは、非公開の型から冗長な opaque を削除します。非公開の型では opaque は何の効果も持ちません。
opaque type Direction {
Up
Down
}opaque の中にカーソルを合わせるとコードアクションが提案され、実行するとモジュールは次のように更新されます。
type Direction {
Up
Down
}冗長なレコード更新の削除(Remove redundant record update)
このコードアクションは、すべてのフィールドが明示的に更新されている冗長なレコード更新を削除します。
pub type User {
User(name: String, likes: List(String))
}
pub fn main() -> List(User) {
let lucy = User(name: "Lucy", likes: ["Gleam", "Ice Cream"])
let jak = User(..lucy, name: "Jak", likes: ["Gleam", "Dogs"])
[lucy, jak]
}2 つ目のレコード更新式の中にカーソルを合わせるとコードアクションが提案され、実行するとモジュールは次のように更新されます。
pub type User {
User(name: String, likes: List(String))
}
pub fn main() -> List(User) {
let lucy = User(name: "Lucy", likes: ["Gleam", "Ice Cream"])
let jak = User(name: "Jak", likes: ["Gleam", "Dogs"])
[lucy, jak]
}冗長なタプルの削除(Remove redundant tuples)
このコードアクションは、case 式の対象とパターンから冗長なタプルを削除します。
case #(a, b) {
#(1, 2) -> todo
_ -> todo
}case 式の中にカーソルを合わせるとコードアクションが提案され、実行するとモジュールは次のように更新されます。
case a, b {
1, 2 -> todo
_, _ -> todo
}到達不能な節の削除(Remove unreachable clauses)
このコードアクションは、case 式から到達不能な節を削除します。
pub fn main() {
case find_user() {
Ok(person) -> todo
Ok(Admin) -> todo
Ok(User) -> todo
Error(_) -> todo
}
}いずれかの到達不能な節の中にカーソルを合わせるとコードアクションが提案され、実行するとモジュールは次のように更新されます。
pub fn main() {
case find_user() {
Ok(person) -> todo
Error(_) -> todo
}
}未使用の import の削除(Remove unused imports)
このコードアクションは、モジュールから未使用の import 文を削除します。
import gleam/io
import gleam/list
pub fn main() {
io.println("Hello, Joe!")
}未使用の import gleam/list の中にカーソルを合わせるとコードアクションが提案され、実行するとモジュールは次のように更新されます。
import gleam/io
pub fn main() {
io.println("Hello, Joe!")
}_ を型に置き換える(Replace _ with type)
このコードアクションは、型注釈内の型ホールを完全な型に置き換えます。
pub fn numbers() -> List(_) {
[1, 2, 3]
}_ の中にカーソルを合わせるとコードアクションが提案され、実行するとモジュールは次のように更新されます。
pub fn numbers() -> List(Int) {
[1, 2, 3]
}ラベル省略記法を使う(Use label shorthand syntax)
このコードアクションは、呼び出しやパターンをラベルの省略記法に更新します。
case date {
Day(day: day, month: month, year: year) -> todo
}省略記法が使用可能な呼び出し内にカーソルを合わせるとコードアクションが提案され、実行するとモジュールは次のように更新されます。
case date {
Day(day:, month:, year:) -> todo
}ブロックで包む(Wrap in block)
このコードアクションは、代入の値や case 式の節の値をブロックで包み、式を追加しやすくします。
pub fn f(pokemon_type: PokemonType) {
case pokemon_type {
Water -> soak()
Fire -> burn()
}
}soak の呼び出しの中にカーソルを合わせるとコードアクションが提案され、実行するとモジュールは次のように更新されます。
pub fn f(pokemon_type: PokemonType) {
case pokemon_type {
Water -> {
soak()
}
Fire -> burn()
}
}セキュリティ
言語サーバはコード生成を行わず、Erlang や Elixir のコードもコンパイルしません。そのため、Gleam 言語サーバを利用しているエディタでファイルを開いたとしても、コードが予期せず実行される危険性はありません。
Gleam プロジェクトの外での利用
言語サーバは、Gleam プロジェクトに属していない Gleam のコードをビルドできません。そのようなファイルを開いた場合、言語サーバはコードの整形を提供しますが、それ以外の機能は利用できません。