コンテンツにスキップ

VSCode extension — first-party marketplace client for `rigor lsp`

ステータス:ドラフト。まだスライスされていない。将来ADRが開かれた場合にのみそれによって置き換えられる。

Language Server(docs/design/20260517-language-server.md)はv0.1.6で着地し、rigor lspサブコマンドとしてrigortype gemにバンドルされている(ADR-19)。今日のVSCodeユーザーは、汎用LSPクライアントか手書きの最小限の拡張機能を通じてそれを配線するように案内されている — 現行のdocs/manual/09-editor-integration.md §「VSCode」を参照。Neovimには文書化されたlspconfigレシピがあり、Helixにはlanguages.tomlブロックがあり、EmacsにはEglot / lsp-modeのスニペットがある。VSCode — Ruby人口の中で単独最大のエディタ — には「自分で書け」というプレースホルダーがある。

このドキュメントは、マーケットプレイスに公開するファーストパーティのVSCode拡張機能を設計する: ワンクリックインストール、設定UI、まともなサーバーディスカバリー、そしてステータスインジケータ。これはADR-19のgem側の決定に対する、エディタ側の対となるものである。

位置づけ — なぜこれはADR-19の問題ではないのか

Section titled “位置づけ — なぜこれはADR-19の問題ではないのか”

ADR-19はLSP gemのコードがどこに置かれるかを決定したが、その支配的な論拠は内部APIの結合だった: LSPはAnalysis::RunnerScope#type_ofEnvironmentBufferTableなどを直接読んでいるため、それを別のgemに分割するとそれらのサーフェスを公開せざるをえなくなる。

その論拠はVSCode拡張機能には移転しない。拡張機能は純粋なLSPクライアントである。それはstdio越しにJSON-RPCでrigor lspと話し、RigorのRuby APIにはまったく触れない。伏せるべき結合はなく、公開APIの誓約も賭けられていない。したがってTypeScriptアーティファクトのパッケージング問題は、それ自体の論点(発見可能性、ビルドツールチェーン、リリース頻度)で答えられ、このドキュメントに記録される。専用のADRはオプションである。もしマーケットプレイス公開のポリシーが後でADRの重みを必要とするなら、gemの論拠を再導出するのではなく、ADR-19にエディタアーティファクトのセクションを追記すればよい。

  • 配置: モノレポ、新しいトップレベルのeditors/vscode/。新しいeditors/ツリーがplugins/examples/skills/に加わる。これにより拡張機能はdocs/lsp-integration.mdの隣でバージョン管理され、1つのリポジトリで発見可能となり、またeditors/を将来のエディタアーティファクト(Zed拡張機能、Emacsパッケージ)のためにレイアウトを蒸し返すことなく予約する。却下したもの: plugins/(そのツリーはplugins/README.mdに従えばRuby gemのプラグインカタログである — TypeScriptアーティファクトはそのカタログの前提を壊す)と、別個のrigor-vscodeリポジトリ(結合がないにもかかわらず、ドキュメント / 拡張機能のリポジトリをまたいだ同期を強いる。結合がないのだから利点はない)。
  • 言語: TypeScript。VSCode拡張機能の標準。
  • クライアントライブラリ: vscode-languageclient(Microsoft)。LSPのライフサイクル、ケイパビリティ折衝、そして診断 / ホバー / 補完 / documentSymbol → VSCode UIの配管をラップする。拡張機能はサーバーを起動しクライアントを登録する。それ自体は言語機能を一切実装しない。
  • サーバートランスポート: stdio。LSPのv1で唯一のトランスポートに合わせる。
  • ビルド: esbuildバンドル+パッケージングのための@vscode/vsce。最小限のツールチェーン。editors/vscode/配下のnpmスクリプト。
  • リリース頻度はgemとは独立している。拡張機能は独自のsemverラインと独自のCHANGELOG.mdを持つ。それはロックステップなバージョンではなく、互換性のある最小rigortypeバージョンを宣言する — LSPのワイヤサーフェスは安定したLSPであるため、拡張機能のUX変更(設定、ステータスバー)がgemのバンプを強いてはならず、アナライザーの型正しさのリリースが拡張機能のバンプを強いてはならない。TypeScriptアーティファクトに適用された、ADR-19の可逆性 / 独立した頻度の論拠を反映している。
  • VS MarketplaceとOpen VSXの両方に公開する。Open VSXはVSCodium / Cursor / Gitpodをカバーする。両方の公開は手動かつ認可ゲート付きであり、gemに対するrake releaseと同じ規律である。
  • 拡張機能はgemをバンドルしない。ユーザーがrigortypeをインストールする(Gemfileまたはグローバルgem)。拡張機能は薄いクライアントである。インストールされていないケースは穏当に処理される(§ サーバーディスカバリーを参照)。
  • マーケットプレイスのパブリッシャー: Rigor組織のパブリッシャーID。
  • 拡張機能ID: rigor。表示名: 「Rigor — Ruby type checker」
  • カテゴリー: Programming LanguagesLinters
  • キーワード: rubyrbstype checkingstatic analysislsp

拡張機能がVSCodeユーザーに与えるもの

Section titled “拡張機能がVSCodeユーザーに与えるもの”

LSPがすでにアドバタイズしているものはすべて、vscode-languageclientが接続すれば自動的に有効になる — 拡張機能はこれらのために機能コードを一切書かない:

LSPケイパビリティそれが駆動するVSCode UI
publishDiagnosticsProblemsパネル+インラインの波線、source: "rigor"、重大度マッピング済み、code = ルールID
hoverホバーツールチップ(型を考慮したmarkdown)
completion. / ::の後のIntelliSense
documentSymbolアウトラインビュー+パンくず+シンボル検索
didChangeWatchedFiles設定 / ファイル保存による無効化(§ ファイルウォッチングを参照)

拡張機能自身のサーフェスは、LSPがstdioサーバーの内側からは提供できない部分である: ディスカバリー、設定UI、ライフサイクルコマンド、ステータス。

拡張機能はrigor実行ファイルを見つけ出さなければならない。優先順位の連鎖、最初にマッチしたものが勝ち、ワークスペースフォルダごとに評価される:

  1. rigor.server.path設定 — 明示的な絶対パスまたはコマンド。非標準のインストール(asdfのshim、モノレポのサブディレクトリ、Dockerのラッパー)のための脱出ハッチ。
  2. Bundlerrigor.server.useBundlerがtrueに解決され、かつそのフォルダにrigortypeを列挙したGemfile.lockがある場合 → bundle exec rigor lspuseBundlerauto / always / neverのenumである。auto(デフォルト)は、rigortypeに言及するGemfile.lockが見つかった場合にかぎりtrueに解決される。ほとんどのRubyプロジェクトはGemfileにgemをピン留めするため、これが一般的なパスである。
  3. グローバルなPATH — むき出しのrigor lsp
  4. 見つからなかった場合 — クラッシュしない。アクション可能な通知(「Rigor: rigortype gem not found in this workspace」)を、インストールドキュメントへリンクするボタン付きで表面化する。拡張機能はロードされたままになるため、ユーザーはGemfileを修正してRigor: Restart Serverを実行できる。

サーバーの作業ディレクトリ=ワークスペースフォルダのルートであるため、Configuration.discoverはCLIとまったく同じように.rigor.yml / .rigor.dist.ymlをたどる。起動時に拡張機能はrigor versionをプローブし(安価)、それが最小値より古ければ警告する — 正確な「gemが古すぎる」というメッセージは、不透明な起動失敗に勝る。

Windowsについての注記: bundle execの解決にはbundle.bat / shell: trueの処理が必要である。LSP自身のWindowsパスエンコーディングのオープンクエスチョン(20260517-language-server.md §「Open questions」)は、ここで解決されるのではなく継承される。

contributes.configuration、すべてrigor.プレフィックスの下:

設定デフォルト効果
rigor.enablebooleantrueマスタースイッチ。falseでクライアントを停止する
rigor.server.pathstring""明示的な実行ファイルのパス / コマンド
rigor.server.useBundlerenum auto/always/neverautoBundlerの解決ポリシー
rigor.server.configPathstring""--config=PATHとして渡される
rigor.server.logPathstring""--log=PATHとして渡される
rigor.trace.serverenum off/messages/verboseoff出力チャンネルへの標準的なLSPクライアントのワイヤトレース

意味のあるところではresourceスコープにしてあるため、マルチルートワークスペースはフォルダごとにオーバーライドできる。

再起動のセマンティクスプロセスの起動方法を変える設定(server.pathserver.useBundlerserver.configPathserver.logPath)はクライアントの再起動を必要とする — それらはworkspace/didChangeConfigurationのペイロードではない。拡張機能は自身の設定をウォッチし、影響を受けるクライアントを自動的に再起動する。LSP v1はdidChangeConfigurationペイロードを無視し、いずれにせよConfiguration.discoverを再実行するため、プロジェクト設定のサーフェスはVSCode設定ではなくファイルウォッチングによって駆動される。

vscode-languageclientは、サーバーがリクエストするworkspace/didChangeWatchedFilesの動的登録を尊重する。拡張機能はさらに**/.rigor.yml**/.rigor.dist.yml**/Gemfile.lockに対してsynchronize.fileEventsを設定するため、設定の編集とgemの変更がサーバーに届き、そのProjectContextを無効化する(LSP設計の §「Project context refresh」に従う)。バッファの編集は通常のdidChangeを通る — ウォッチャは不要である。

activationEvents:

  • onLanguage:ruby
  • workspaceContains:**/.rigor.yml
  • workspaceContains:**/.rigor.dist.yml

*によるイーガーアクティベーションはなし — VSCodeの起動パフォーマンスガイダンス。Rigor設定を持つプロジェクトは最初のRubyファイルが開かれる前にサーバーをウォームアップする。設定を持たないプロジェクトは、Rubyに触れたときにのみアクティベートされる。

contributes.commands:

  • rigor.restartServer — 言語クライアントを再起動する(gemのアップデート、Gemfileの変更、またはサーバーに影響する設定の編集の後)。
  • rigor.showOutputChannel — 「Rigor」出力チャンネルを表示する。
  • rigor.showServerLogserver.logPathが設定されている場合に--logファイルを開く。

延期されたもの(§ スコープ外を参照): rigor.checkWorkspace

ステータスバーアイテムがクライアントの状態 — starting / running / stopped / error — を反映し、それをクリックすると出力チャンネルが開く。LSPはそれ以外では静かに動作するため、これが主要な「生きているか?」のアフォーダンスとなる。標準的な形状である(Sorbet / Steepの拡張機能も同じことをしている)。

LSP v1はシングルルートである(20260517-language-server.md §「Out of scope for v1」)。拡張機能はそれをVSCodeのマルチルートワークスペースと折り合わせるため、.rigor.yml / .rigor.dist.yml / Gemfileを含むワークスペースフォルダごとに1つのLanguageClientを、それぞれそのフォルダをルートとして起動する。Rigor設定を持たないフォルダはクライアントを得ない。すべてのRigor設定済みフォルダの外にあるファイルは診断を得ない — 既知の制限として文書化されており、LSPが後でマルチルートサポートを得れば無償で解消される。

documentSelector: { scheme: 'file', language: 'ruby' }。Untitledおよび非fileバッファはサポートされない — アナライザーはディスク上のプロジェクトルートを必要とする。

VSCodeユーザーはShopify Ruby LSP / Solargraph / Sorbetを日常的に並べて実行している。VSCodeは言語ごとに複数のサーバーを衝突なく多重化する。良き市民であり続けるため、Rigor拡張機能は:

  • contributes.languages / grammars宣言しない — 既存のruby言語IDを消費するだけで、それを主張することは決してない(シンタックスハイライトはユーザーが選んだgrammar拡張機能のままになる)。
  • フォーマッタを登録しない(LSP設計に従えばRuboCopの仕事である)。
  • Problemsパネルでの視覚的な帰属のために、すべての診断のsource: "rigor"に依存する。

READMEは、もう一つのRuby LSPも実行するユーザーのためにペアリングのセットアップを推奨する。

  • rigor.checkWorkspace — プロジェクト全体のrigor check実行。LSPは単一ファイルのスコープである。プロジェクト全体の診断はエディタモードの「オプションB」フォローアップ(ROADMAP §「Editor / IDE integration」)に属する。LSPがワークスペース診断を公開すれば明示的なコマンドは冗長になる — それまで延期する。それより早く要求されるなら、コマンドではなくcontributes.tasksのタスクとして出荷する。
  • バンドルされたrigortype — gemはユーザーがインストールするものである。
  • テレメトリ — なし。プライバシーのために明示的に述べておく。
  • デバッグアダプタ / テストランナー統合
  • スニペット、コードレンズ、インレイヒント — 対応するLSPケイパビリティを待つ(すべてROADMAPにキューされている)。

editors/vscode/の内容:

editors/vscode/
package.json extension manifest + contributes
tsconfig.json
esbuild.js bundle script
src/extension.ts activate / deactivate, client wiring
src/discovery.ts server-discovery chain
src/status.ts status bar item
.vscodeignore
README.md marketplace landing page
CHANGELOG.md extension's own semver line
LICENSE
icon.png
  • ビルド: npm run compile(esbuild)。パッケージ: npm run packagevsce package.vsix)。
  • 公開: vsce publish(VS Marketplace)+ovsx publish(Open VSX)。手動かつ認可ゲート付きbundle exec rake releaseと同じルール。これをgemリリースのゲートと並べてAGENTS.mdに記録する。
  • CI: editors/vscode/にスコープされたGitHub Actionsジョブがnpm ci && npm run compile && npm run packageを実行し、破損を捕まえる。公開は手動のままである。
  • 拡張機能のビルドはmake verifyに配線されておらず、NodeはFlakeのdevシェルに追加されない — Ruby貢献者にNodeツールチェーンを強いてはならない。editors/vscode/は独自のnpmスクリプトを抱える。AGENTS.mdがこの分離を文書化する。(ADR-19との対称性: あちらではCIのみのgemユーザーが依然としてlanguage_server-protocolの依存を負担する。こちらではRuby貢献者がNodeの依存を負担しない。)
  • VSCodeのengines.vscode: 最近の^1.8x.0をベースラインとする。
  • vscode-languageclient: メジャーバージョンをピン留めする。
  • 最小のrigortype: v0.1.6rigor lspを出荷した最初のリリース)。起動時のrigor versionプローブがそれを強制する。
  • 位置エンコーディング: LSPはVSCodeのデフォルトであるutf-16をアドバタイズする — 折衝の問題はない。

各スライスは独自のコミットで出荷される。LSP設計と同じ規律である。

  1. editors/vscode/のスキャフォールドpackage.jsontsconfigesbuild.js、hello-worldのactivate。LSPはまだなし。
  2. LanguageClientの配線 — stdio越しにrigor lspを起動、documentSelectorはruby。診断 / ホバー / 補完 / アウトラインが有効になる。最初のユーザーから見える成果。
  3. 設定のコントリビューション — 設定 → サーバー引数(--config--log)。サーバー設定変更時の再起動。
  4. サーバーディスカバリーの連鎖path / bundler-auto / グローバル+アクション可能な「見つからない」通知+rigor versionプローブ。
  5. ステータスバーアイテム+コマンドrestartServershowOutputChannelshowServerLog
  6. マルチルート — Rigor設定済みフォルダごとに1つのクライアント。
  7. ファイルウォッチング.rigor.yml / Gemfile.lockの同期。
  8. マーケットプレイスのメタデータ — README、アイコン、カテゴリー、キーワード。Open VSXのマニフェスト。
  9. CIジョブ — ビルド+vsce package(公開なし)。
  10. (延期) rigor.checkWorkspaceタスク。新しいLSP機能を追跡するケイパビリティのフォローアップ。

スライス7の後、拡張機能は「マーケットプレイスからインストールし、キーストロークのように速い診断+ホバー+補完+アウトラインを得る」体験について機能完成となる。スライス8〜9は公開のパスである。

ドキュメントのフォロースルー

Section titled “ドキュメントのフォロースルー”

拡張機能が出荷されたら、docs/manual/09-editor-integration.md §「VSCode」を書き換える: 汎用クライアント / 手書き拡張機能のワークアラウンドを「マーケットプレイス(またはOpen VSX)からRigor拡張機能をインストールする」に置き換え、手動配線のスニペットはサポート外のVSCodeフォークを使うユーザーのためのフォールバックとしてのみ残す。

  • Open VSXの自動化 — 自動化されたovsx publishのためのトークン保管 / ローテーション。延期。v1は手動で公開する。
  • アイコン / ブランディングアセット — 最初のマーケットプレイス提出の前に、実際にデザインされたアセットが必要である。
  • rigor versionプローブの失敗モード — 「gemが不在」を「gemは存在するがlspサブコマンドが不在」(v0.1.6以前)と「OSによって起動がブロックされた」から区別する。v1は後者2つを1つのメッセージにまとめる。ユーザーを混乱させるなら精緻化する。
  • プレリリースチャンネル — VS Marketplaceはpre-releaseフラグをサポートする。未リリースのLSPケイパビリティを追跡するためにそれを使うかどうかを決める。プレビューに値するLSP機能が出るまで延期する。
  • ワークスペーストラスト — VSCodeの「制限モード」はワークスペースの実行ファイルの起動をブロックする。拡張機能は信頼されていないワークスペースを検出し、静かに失敗するのではなく明確な「Rigorを実行するためにこのワークスペースを信頼してください」というプロンプトを表示すべきである。

© 2026 TypedDuck. Licensed under CC BY-SA 4.0.