コード補完

本プラグインは、コードをより速く記述するための複数の補完メカニズムを提供します。

LSP 補完

LSP Required

Language Server は、型を考慮したインテリジェントな補完を提供します。Ctrl+Space(macOS では Cmd+Space)で補完をトリガーするか、入力を開始するだけで補完が表示されます。

補完される項目

  • 変数名と関数名

  • モジュール名とパス

  • レコードフィールド名

  • バリアントコンストラクタ

  • 型名

  • パイプ(->)チェーンの候補

型認識補完により API を暗記する時間が減ります — IDE がコード内の型に基づいて適切な関数、フィールド、コンストラクタを提案します。

Postfix Completion

Native

式の後に . とポストフィックステンプレート名を入力すると、式が変換されます。

テンプレート

入力

出力

.switch

expr.switch

switch expr { | _ => }

.pipe

expr.pipe

expr->

.log

expr.log

Console.log(expr)

.some

expr.some

Some(expr)

.ok

expr.ok

Ok(expr)

.error

expr.error

Error(expr)

.ignore

expr.ignore

expr->ignore

.promise

expr.promise

expr->Promise.then(result => { ... })

.await

expr.await

await expr

注釈

ポストフィックステンプレートはコメントや文字列リテラル内では使用できません。

詳細な使い方

.switch -- パターンマッチング

値に対してパターンマッチが必要なときに .switch を使用します。switch 式は ReScript プログラミングの中核であるため、最も頻繁に使用されるポストフィックステンプレートの 1 つです。

変換前:

status.switch

変換後:

switch status {
| _ =>
}

カーソルは => の後に配置されるため、すぐにブランチの本体を入力できます。追加のアームは手動で追加してください。

.pipe -- 関数合成

パイプチェーンを開始または拡張するために .pipe を使用します。ReScript は 関数呼び出しのチェーンに -> (pipe first) を使用しており、このテンプレートはデータ変換パイプラインを構築する際のキーストロークを節約します。

変換前:

array.pipe

変換後:

array->

カーソルは -> の直後に配置されるため、次の関数名をすぐに入力できます。これはチェーンを構築する際に特に便利です:

users
->Array.filter(u => u.active)
->Array.map(u => u.name)
->Array.sort(String.compare)

.log -- デバッグログ

.log を使用して、デバッグのために式を Console.log() で素早くラップします。

変換前:

result.log

変換後:

Console.log(result)

ラッピング関数を手動で入力することなく、素早くデバッグできるため便利です。

.some -- オプショナル値のラッピング

.some を使用して、option 型の Some コンストラクタで値をラップします。

変換前:

user.name.some

変換後:

Some(user.name)

関数からオプショナル値を返す必要がある場合に便利です:

let findUser = (id) => {
  // ...lookup logic...
  matchedUser.some // becomes Some(matchedUser)
}

.ok / .error -- Result 型のラッピング

.ok.error を使用して、result 型のコンストラクタで値をラップします。

変換前:

parsedData.ok

変換後:

Ok(parsedData)

変換前:

"Invalid input".error

変換後:

Error("Invalid input")

result<'a, 'b> を返す関数を扱う場合に役立ちます:

let validate = (input) => {
  if isValid(input) {
    process(input).ok     // becomes Ok(process(input))
  } else {
    "Bad input".error     // becomes Error("Bad input")
  }
}

.ignore -- 戻り値の破棄

副作用のために関数を呼び出し、戻り値を破棄したい場合に .ignore を使用します。これにより、未使用の値に関するコンパイラ警告を回避できます。

変換前:

Js.Promise.then(promise, handler).ignore

変換後:

Js.Promise.then(promise, handler)->ignore

.promise -- 非同期 Promise チェーン

.promise を使用して、式を Promise.then コールバックでラップします。非同期コードを扱う際に便利です。

変換前:

fetchData().promise

変換後:

fetchData()->Promise.then(result => {
  // cursor here
})

カーソルはコールバック本体の内側に配置されるため、すぐに継続ロジックを記述できます。

.await -- Await 式

.await を使用して、式の前に await を付加し、async 関数内で Promise を解決された値に変換します。

変換前:

fetchData().await

変換後:

await fetchData()

手動でカーソルを移動することなく、Promise 式を await する最も素早い方法です。

Postfix テンプレートを使えば、カーソルを先頭に戻さずに式を変換できます — まず式を入力し、その後変換を適用することで、自然な左から右への入力フローを維持できます。

参考

Code Editing では、さらに多くのコード変換パターンのための Intention アクションと Surround With を提供しています。

Live Templates

Native

スニペットの省略形を入力して Tab を押すと展開されます。カーソルは各プレースホルダー(以下の展開例に表示)で停止し、Tab を押すと次のプレースホルダーに移動します。

省略形

説明

展開

let

let バインディング

let name = value

letfn

let 関数定義

let name = (params) => { ... }

mod

モジュール定義

module Name = { ... }

modt

モジュール型定義

module type Name = { ... }

typ

型定義

type name = ...

typr

レコード型

type name = { field: type, ... }

typv

バリアント型

type name = | Variant ...

sw

switch 式

switch expr { | pattern => ... }

if

if 式

if condition { ... }

ife

if-else 式

if condition { ... } else { ... }

try

try-catch 式

try { ... } catch { | exn => ... }

for

for ループ

for i in 0 to 10 { ... }

ext

external (FFI)

external name: type = "jsName"

pipe

パイプ演算子

->func(...)

log

Console.log

Console.log(...)

@module

@module external バインディング

@module("name") external fn: 'a = "default"

@val

@val external バインディング

@val external name: 'a = "name"

@send

@send external バインディング

@send external name: (obj, 'a) => unit = "name"

@get

@get external バインディング

@get external name: obj => 'a = "name"

@set

@set external バインディング

@set external name: (obj, 'a) => unit = "name"

comp

React コンポーネント

@react.component let make = (~children) => { ... }

テンプレートの詳細

宣言

let -- let バインディング

let name = value

カーソルはまず name で停止し、次に value で停止します。

letfn -- 関数定義

let name = (params) => {
  // cursor here
}

カーソルは nameparams、関数本体の順に停止します。

mod -- モジュール定義

module Name = {
  // cursor here
}

modt -- モジュール型定義

module type Name = {
  // cursor here
}

型定義

typ -- 単純な型エイリアス

type name = // cursor here

typr -- レコード型定義

type name = {
  field: string,
  // cursor here
}

カーソルは namefield、フィールドの型、レコード内部(追加フィールド用)の順に停止します。

typv -- バリアント型定義

type name =
  | Variant // cursor here

カーソルは nameVariant の順に停止し、最初のコンストラクタを定義してさらに追加できます。

制御フロー

sw -- switch 式

switch expr {
| pattern => // cursor here
}

if -- if 式

if condition {
  // cursor here
}

ife -- if-else 式

if condition {
  // then branch
} else {
  // cursor here
}

try -- try-catch 式

try {
  // cursor here
} catch {
| exn => ()
}

for -- for ループ

for i in 0 to 10 {
  // cursor here
}

カーソルはループ変数 i、開始値 0、終了値 10、ループ本体の順に停止します。

FFI (Foreign Function Interface)

ext -- external 宣言

external name: 'a = "jsName"

カーソルは name、型アノテーション、JavaScript の名前文字列の順に停止します。JavaScript の関数や値へのバインディングに便利です。

ユーティリティ

pipe -- 関数呼び出し付きパイプ演算子

->func()

式の後に入力して関数にパイプします。カーソルは func で停止し、次に括弧内の引数部分で停止します。

log -- Console.log

Console.log()

カーソルは括弧の内側に配置されます。

FFI バインディングテンプレート

@module -- モジュールバインディング

@module("module-name")
external name: 'a = "default"

カーソルはモジュール名、バインディング名、型、JavaScript エクスポート名の順に停止します。

@val -- グローバル値バインディング

@val external name: 'a = "name"

@send -- メソッドバインディング

@send external name: (obj, 'a) => unit = "name"

カーソルはバインディング名、レシーバーオブジェクト型、パラメータ型、戻り値型、JavaScript メソッド名の順に停止します。

@get -- プロパティ getter バインディング

@get external name: obj => 'a = "name"

@set -- プロパティ setter バインディング

@set external name: (obj, 'a) => unit = "name"

React

comp -- React コンポーネント

@react.component
let make = (~children) => {
  // cursor here
}

カーソルは props パラメーターで停止し、次にコンポーネント本体で停止します。

カスタマイズ

すべての ReScript Live Templates は Settings | Editor | Live Templates | ReScript でカスタマイズできます。ここから以下の操作が可能です:

  • 既存のテンプレート展開とプレースホルダー変数を編集する

  • 新しいテンプレートを追加する

  • 省略形のトリガーテキストを変更する

  • 使用しないテンプレートを無効にする

Live テンプレートは反復的なボイラープレートを排除します — switchif-else@module バインディング、React コンポーネントなどの共通パターンをゼロから入力する代わりに、短い略語がプレースホルダーナビゲーション付きの完全な構造に展開されます。

Completion Weigher

LSP Required

プラグインはコンテキストに基づいた補完候補の優先順位付けを提供し、最も関連性の高い候補が補完ポップアップの先頭に表示されるようにします。

仕組み

Language Server が補完候補を返すと、Completion Weigher がコンテキストの手がかりに基づいて候補を並べ替えます:

  • 局所性 --- 現在のファイルまたはモジュールで定義されたシンボルが、外部インポートよりも優先されます

  • 型の互換性 --- 挿入位置で期待される型に一致する候補がブーストされます

  • 直近の使用 --- 最近使用した補完候補がより上位にランクされます

  • パイプコンテキスト --- -> パイプチェーン内では、第一引数がパイプ入力の型に一致する関数が優先されます

これにより、補完をトリガーすると、スクロールや追加のフィルター文字を入力することなく、通常はリストの先頭に最も有用な候補が表示されます。

let names: array<string> = ["Alice", "Bob", "Charlie"]

names->  // Completion popup prioritizes Array functions:
         // Array.map, Array.filter, Array.forEach, ...
         // over unrelated functions like String.length

スマートランキングにより、必要な補完候補は通常リストの先頭に表示され、正しい候補を選択するために必要なキーストローク数が減ります。

パイプチェーン型ヒント

LSP Required

-> パイプチェーンを記述する際、プラグインは各パイプステップ間に中間型ヒントを表示し、変換チェーンを通じたデータフローを容易に理解できるようにします。

users                          // : array<user>
->Array.filter(u => u.active)  // : array<user>
->Array.map(u => u.name)       // : array<string>
->Array.sort(String.compare)   // : array<string>
->Array.length                 // : int

各インレイヒントはチェーン内のその時点での式の型を表示するため、各ステップでデータがどのように変換されるかを追跡できます。

設定

パイプチェーン型ヒントはインレイヒントとして表示されます。表示/非表示は Settings > Editor > Inlay Hints > ReScript で設定できます。

要件

この機能は Language Server が起動している必要があります。パイプチェーン内の各中間式の型情報は LSP hover リクエストを介して取得されます。

データ変換パイプラインを構築する際、中間型ヒントにより各ステップが期待される型を生成していることを確認でき、チェーンの最後ではなく途中で変換エラーをキャッチできます。

Parameter Info

LSP Required

関数呼び出し内で Ctrl+P(macOS では Cmd+P)を押すと、ネイティブ IDE ポップアップにラベル付き引数の情報が表示されます。

仕組み

関数呼び出しの括弧内で Parameter Info を呼び出すと、プラグインは Language Server から hover 情報をリクエストし、関数シグネチャを解析してラベル付き引数を抽出します。結果は現在のパラメータ位置をハイライトしたネイティブポップアップで表示されます。

let makeConfig = (~host: string, ~port: int, ~debug: bool=?) => {
  // ...
}

makeConfig(~host="localhost", | )
//                             ^ Ctrl+P here shows:
//                               ~host: string, ~port: int, ~debug: bool=?
//                               with ~port highlighted as the next expected argument

Signature Help との違い

機能

トリガー

ソース

Signature Help

( 入力時に自動表示

LSP textDocument/signatureHelp

Parameter Info

Ctrl+P で手動表示

LSP textDocument/hover + 引数解析

Parameter Info は、最初の Signature Help ポップアップが閉じた後に期待される引数を確認したい場合や、既存の関数呼び出しに戻って確認する場合に便利です。

Parameter Info は現在の編集位置を離れることなく、関数のラベル付き引数にオンデマンドでアクセスでき、関数定義を確認せずに正しくパラメータを入力できます。

Signature Help

LSP Required

関数名の後に ( を入力すると、型や名前を含む関数のパラメータ情報がポップアップで表示されます。ドキュメントを確認せずに引数を正しく入力するのに役立ちます。

たとえば、以下の関数がある場合:

let makeUser = (name: string, age: int, ~role: string=?) => {
  // ...
}

makeUser( と入力すると Signature Help のポップアップがトリガーされ、以下が表示されます:

(name: string, age: int, ~role: string=?) => user

各引数を入力してカンマを入力するたびに、ポップアップは現在のパラメータ位置をハイライトするため、どの引数を入力しているかが常にわかります。これは、標準ライブラリ関数や独自の定義を含め、Language Server がシグネチャを把握しているすべての関数で動作します。

Signature Help は関数呼び出しの推測を排除します — 入力中にパラメータの型と名前がインラインで表示され、引数の順序や型の不一致によるエラーが減ります。

Completion Confidence

Native

プラグインは、補完が役に立たないまたは邪魔になるコンテキストでは自動補完ポップアップを抑制します:

  • コメント内 — 行コメント(//)、ブロックコメント(/* */)、ドキュメントコメント(/** */

  • 文字列リテラル内 — 通常の文字列、テンプレート文字列、文字リテラル

これらのコンテキストでも Ctrl+Space で手動で補完をトリガーできますが、入力中にポップアップが自動的に表示されることはありません。これにより、ドキュメントや文字列の記述が無関係な候補によって中断されるのを防ぎます。

これにより補完ポップアップは本当に有用な場合にのみ表示され、コメントや文字列の記述が無関係なコード提案に中断されることがなくなります。

入力文字フィルター

Native

プラグインは入力された文字に基づいて補完の動作をインテリジェントにフィルタリングします:

  • . を入力すると、現在の補完を確定してドットを挿入します(モジュールアクセスパターン用)

  • ( を入力すると、現在の補完を確定して括弧を挿入します(関数呼び出し用)

  • その他の特殊文字は ReScript 構文に適した動作をします

スマートな文字処理により、補完から次の編集アクションへ自然に移行できます — . でモジュールを受け入れたり ( で関数を受け入れたり — ポップアップを先に閉じるための追加キーストロークは不要です。