PI DOCUMENTATION / 日本語
ターミナル UI
@earendil-works/pi-tui は、Pi が使用するターミナルコンポーネントシステムを提供します。組み込みのダイアログ、通知、ステータステキスト、ウィジェットでは必要な操作を実現できない場合に、拡張機能で使用します。
まず、拡張機能から ctx.ui のメソッドを使用します。UI に独自のレンダリング、キーボードまたはマウス入力、フォーカス、レイアウト、ライフサイクルが必要な場合にのみ、カスタムコンポーネントを構築します。
統合ポイントの選択#
| ニーズ | 使用するもの |
|---|---|
| 選択、確認、入力、または複数行エディター | ctx.ui.select()、confirm()、input()、または editor() |
| 非ブロッキングのフィードバック | ctx.ui.notify() または setStatus() |
| エディター付近の永続的なコンテンツ | ctx.ui.setWidget() |
| ヘッダー、フッター、またはエディターの置き換え | 対応する ctx.ui コンポーネントファクトリー |
| 一時的な対話画面またはオーバーレイ | ctx.ui.custom() |
| ツールまたはセッションエントリのカスタムレンダリング | 拡張機能のレンダラー |
これらの API には、必要に応じて Pi のアクティブなテーマとキーバインドが渡されます。拡張機能内に別のターミナルレンダラーを作成しないでください。
コンポーネントモデルを理解する#
コンポーネントは、利用可能な幅に合わせてターミナル行の配列をレンダリングします。必要に応じてキーボード入力とマウス入力を処理でき、状態またはテーマ依存のコンテンツが変更された場合は、キャッシュされた出力を無効化する必要があります。
レンダリングされる各行は、指定された幅に収まる必要があります。ANSI エスケープ、全角文字、絵文字、結合文字によって表示幅が変わるため、文字列の長さではなく、ターミナル上で表示される列数を測定してください。
ターミナル幅の処理を独自に実装する代わりに、visibleWidth()、truncateToWidth()、sliceByColumn()、wrapTextWithAnsi() を使用してください。Pi は各行の後でスタイルとハイパーリンクをリセットするため、レンダリングする行ごとにスタイルを再適用してください。
コンポーネントの状態を変更した後は、影響を受けるコンポーネントを無効化し、注入された tui.requestRender() を呼び出します。TUI はレンダリング要求をまとめて処理し、ターミナルを更新します。
組み込みコンポーネントを組み合わせる#
このパッケージには、一般的なレイアウトとコントロール用のコンポーネントが含まれています。
Text、Markdown、Image、TruncatedTextはコンテンツをレンダリングします。Container、VStack、HStack、Box、Spacerはレイアウトを構成します。InputとEditorはテキストを受け取ります。SelectListとSettingsListは、検索可能な選択フローと設定フローを実装します。ScrollViewは、範囲が制限されたスクロール可能なビューポートを提供します。LoaderとCancellableLoaderは、進行中の処理を示します。MouseRegionは、別のコンポーネントにポインター操作を追加します。
選択、スクロール、テキスト編集、幅の処理を再実装するよりも、これらのコンポーネントを優先してください。拡張機能の例では、Pi の境界線やテーマと組み合わせる方法を示しています。
キーボード入力とフォーカスを処理する#
ターミナルのキーボード入力には matchesKey() と Key を使用してください。パーサーは、サポートされているターミナルプロトコルと修飾キーを考慮します。拡張機能のコンポーネントでは、設定可能なアプリケーションアクションに、注入された KeybindingsManager を使用してください。
テキストカーソルを表示するコンポーネントは Focusable を実装し、視覚的なカーソルの直前に CURSOR_MARKER を配置する必要があります。TUI はこのマーカーを使用して、インプットメソッドエディター用のハードウェアカーソルを配置します。
Input または Editor をラップするコンテナーは、その focused 状態を子コンポーネントへ伝播する必要があります。伝播しない場合、中国語、日本語、韓国語などの IME 候補ウィンドウが画面上の誤った位置に表示される可能性があります。
メインエディターを置き換える場合は、Pi の CustomEditor を拡張してください。これにより、アプリケーションのショートカットとエージェントのコントロールが維持されます。
エディターが処理しないキーは基底実装に転送し、カスタムエディターファクトリーをクリアしてデフォルトに戻してください。
マウス入力を処理する#
フルスクリーンモードでは、正規化されたマウスイベントがコンポーネントに送られます。ハンドラーは、イベントを処理済みとしてマークする、ドラッグシーケンスをキャプチャする、フォーカスを要求する、またはレンダリングを要求できます。
未処理のホイールイベントは、最も近い ScrollView をスクロールします。未処理の第1ボタンによるドラッグは、引き続きトランスクリプトの選択に使用できます。OSC 8 リンクは、それを囲むクリック領域よりも優先されます。
通常モードでは、スクロールバックをターミナルが管理するため、マウス入力はターミナルに委ねられます。フルスクリーンのマウス入力を利用できる場合でも、すべての操作にキーボードでの操作経路を用意してください。
カスタム画面とオーバーレイを使用する#
ctx.ui.custom() は、1つのコンポーネントに対話領域の制御を一時的に委ね、そのコンポーネントが提供された完了コールバックを呼び出すと解決されます。
既存のコンテンツの上に描画するには、overlay: true を渡します。オーバーレイオプションでは、サイズ、アンカー、オフセット、マージン、レスポンシブ表示を制御します。操作がアクティブな間、オーバーレイハンドルはフォーカスを変更したり、setHidden() でオーバーレイを一時的に非表示または再表示したりできます。
フォーカスされたオーバーレイは、通常のレンダリングをまたいで入力の所有権を維持します。オーバーレイを表示したまま別のコンポーネントに入力を受け取らせる場合は、ハンドルを通じてフォーカスを明示的に解放またはリダイレクトしてください。
各カスタムコンポーネントのインスタンスは、1つの操作に属するものとして扱ってください。その操作を再度開始するときは、新しいインスタンスを作成してください。
コンポーネントファクトリーに提供された完了コールバックで操作を終了してください。これにより、ctx.ui.custom() の Promise が解決され、コンポーネントが破棄されます。ctx.ui.custom() で作成されたオーバーレイに対して OverlayHandle.hide() を呼び出さないでください。
配置、積み重ね順、フォーカス、レスポンシブ表示、アニメーションの動作については、overlay-qa-tests.ts を参照してください。
テーマを正しく適用する#
拡張機能またはコンポーネントのコールバックに渡されたテーマを使用してください。テーマヘルパーは、アクセント、控えめなテキスト、成功、警告、エラー、ツール出力、Markdown などの意味的な色に対応する ANSI スタイル付き文字列を生成します。
前景色と背景色をテキスト属性と組み合わせるには、theme.style() を使用します。
return new Text(
theme.style("Done!", {
fg: "success",
bg: "toolSuccessBg",
bold: true,
}),
0,
0,
);スタイルの色には、意味的なテーマトークンまたは具体的な Color を指定できます。前景色トークンは fg、背景色トークンは bg として受け付けられます。トークンの色を反対側の位置で使用するには、たとえば { fg: theme.colors.userMessageBg } のように具体的な色を渡します。具体的な色には theme.colors を介してアクセスし、色の計算が必要な場合は @earendil-works/pi-tui の mixColors() などのユーティリティを使用してください。テーマでターミナルのデフォルトに設定されたトークンは、ターミナル独自の色でレンダリングされます。theme.colors は、そのトークンについてターミナルが通知した色を返し、通知されなかった場合は推定値を返します。たとえば、色を明るくするか暗くするかを決めるには、theme.appearance("dark" または "light")を使用します。Pi はターミナルの機能に応じて、結果をトゥルーカラーまたは256色の出力に変換します。テーマトークンはテーマごとに一度変換されます。可能な場合は、具体的な色をレンダリング処理の外で計算してください。
既存の theme.fg() と theme.bg() のヘルパーも、単一の意味的な色を適用するために引き続き使用できます。
invalidate() によって再構築される場合を除き、テーマカラーを含む文字列を永続的に保存しないでください。テーマを変更するとレンダリングキャッシュはクリアされますが、アプリケーションの状態に埋め込まれた古い ANSI カラーは削除できません。
レンダリング中に評価されるテーマコールバックには、特別な再構築は必要ありません。ステートレスコンポーネントでも、レンダリングのたびにテーマを適用した出力を計算できます。
ターミナルのカラーパレットを作成するには、テーマを使用してください。アクティブなアプリケーションテーマに合わせる必要がある Markdown をレンダリングする場合は、Pi の getMarkdownTheme() を使用してください。
レンダリングの応答性を維持する#
レンダリングは対話処理の経路上で実行されます。コストの高いレイアウト処理とハイライト処理を幅とコンテンツごとにキャッシュし、invalidate() からそのキャッシュをクリアしてください。
デフォルト表示はコンパクトに保ち、展開または専用画面で詳細を表示してください。カスタムツールのレンダリングでは、部分的な結果を処理し、安全に更新できる場合は以前のコンポーネントを再利用してください。
レンダリングの問題を診断するときは、PI_TUI_WRITE_LOG を使用して生の ANSI ストリームを取得してください。狭い幅、全角文字、サイズ変更イベント、テーマ変更、フォーカス遷移、通常モードとフルスクリーンモードの両方をテストしてください。
例とソース#
確認済みの拡張機能の例では、主要なパターンを扱っています。
preset.tsとtools.tsは、選択リストと設定リストを使用します。qna.tsは、キャンセル可能な非同期 UI を使用します。modal-editor.tsは、エディターを置き換えます。custom-footer.tsは、フッターを置き換えます。widget-placement.tsは、エディターの周囲に永続的なコンテンツを配置します。doom-overlay/は、継続的にレンダリングされるオーバーレイを実演します。
公開エクスポートは packages/tui/src/index.ts で定義されています。拡張機能のライフサイクル、状態、ツール、イベント、モードの動作については、拡張機能を参照してください。