HN 日本語サマリー

← 一覧へ戻る
プログラミング

Rio-vtとlibrio: Rioのターミナルエンジンが組み込み可能に

Rio-vt and librio: Rio's terminal engine, now embeddable (rioterm.com)

46 pointsby vinhnx14 コメント

要約

Rioターミナルのコアエンジンがレンダリング部分から分離され、rio-vt(Rustクレート)とlibrio(C ABI)の2つのレイヤーとして提供されるようになりました。これにより、VT状態マシン、グリッド、スクロールバック、選択、検索、画像プロトコルなどのコア機能が、任意のレンダラーと組み合わせて利用可能になります。librioはC ABI経由で他の言語からも利用でき、クロスプラットフォームで動作します。パフォーマンスベンチマークでは、多くのワークロードで他のパーサーと比較して高速であることが示されています。

全文翻訳

皆さん、こんにちは!しばらくの間、Rioのターミナルコアは、レンダラー、設定、そしてそれを囲むアプリと絡み合っていました。これにより、私自身を含め、誰もが長年かけて正しいものを作り上げた部分(VT状態マシン、グリッド、スクロールバック、選択、検索、画像プロトコル)を再利用するのが困難でした。Rio 0.5でこれが変わります。エンジンはクリーンで組み込み可能なレイヤーに分割され、それらを皆さんに紹介したいと思います:rio-vtとlibrioです。2つのレイヤー​アイデアはシンプルです。ターミナルを必要とするほとんどのプロジェクトは、完全なターミナルアプリを必要としているのではなく、エンジンを必要としています。そのため、エンジンは2つのレイヤーとして提供されます。rio-vtは安全なRustクレートです。VT状態マシン、ANSI/エスケープパーサー、スクロールバック、選択、検索、PTYドライバーを備えたグリッド、そしてSixel / Kitty / iTerm2画像プロトコルが含まれます。レンダリング、GPU、フォントシェーピングはありません。Rustで書いているなら、これを直接依存します。モダンなalacritty_terminalの代替と考えてください。librioは、libghosttyの精神に則り、C ABIの背後にある同じコアです。Swift、C、Go、Python、またはCを話すものなら何でも書いている場合、これをリンクします。これはプリビルドされた静的ライブラリとして提供され、Rustツールチェーンは不要です。すべてのunsafeコードはここにあり、rio-vt自体は安全なRustのままです。どちらもデフォルトで軽量です。rio-vtを機能なしでビルドしても、レンダラー、GPU、フォントシェーピングの依存関係は一切引き込みません。単なるターミナルです。rio-vtの実践​コアは実際のターミナルと同じように駆動されます。バイトをフィードし、グリッド状態をプルアウトします。以下は、PTYやレンダラー、スレッドなしの完全なループです:use rio_vt::ansi::CursorShape;use rio_vt::crosswords::grid::Dimensions;use rio_vt::crosswords::pos::Column;use rio_vt::crosswords::{Crosswords, CrosswordsSize};use rio_vt::event::{VoidListener, WindowId};use rio_vt::performer::handler::Processor;// 10k行のスクロールバックを持つ80x24ターミナル。let size = CrosswordsSize::new(80, 24);let cols = size.columns();let mut term = Crosswords::new( size, CursorShape::Block, VoidListener, WindowId::from(0), 0, 10_000,);// 生のPTYバイトをフィード:SGR赤 "hello"、リセット、次に " world"。let mut parser = Processor::default();parser.advance(&mut term, b"\x1b[31mhello\x1b[0m world");// 表示されているグリッドをプルし、最初の行を読み取ります。let rows = term.visible_rows();let line: String = (0..cols).map(|x| rows[0][Column(x)].c()).collect();assert!(line.starts_with("hello world")); rio-vtは何も描画しないため、グリッドをどうするかはあなたが決定します。任意のレンダラーとペアにするか、全くペアにしないかです。選択と検索は無料で提供されます​use rio_vt::crosswords::pos::{Column, Line, Pos, Side};use rio_vt::selection::{Selection, SelectionType};let mut selection = Selection::new( SelectionType::Simple, Pos::new(Line(0), Column(0)), Side::Left,);selection.update(Pos::new(Line(0), Column(4)), Side::Right);term.selection = Some(selection);assert_eq!(term.selection_to_string().as_deref(), Some("hello")); // 列 0..=4 画像も​Sixel、Kitty、iTerm2の画像送信はコアによってデコードされ、イベントを通じて表面化されるため、フロントエンドは他のものと同じように記録します。以下は、ヘッドレスでキャプチャされたKittyグラフィックスプロトコルトランスミッションです:impl EventListener for ImageSink { fn event(&self) -> (Option<RioEvent>, bool) { (None, false) } fn send_event(&self, event: RioEvent, _: WindowId) { if let RioEvent::UpdateGraphics { queues, .. } = event { for (id, g) in &queues.pending_images { // id, g.width, g.height, g.pixels (RGBA) ... } } }}// f=32 RGBA, 2x2 px, a=T 送信+表示、base64ピクセル:parser.advance(&mut term, b"\x1b_Gf=32,s=2,v=2,a=T;/wAA//8AAP//AAD//wAA/w==\x1b\");// -> kitty画像: id=..., 2x2px, 16 rgbaバイト librio: 同じコアを、どの言語からでも​librioは、そのエンジンを小さなC ABIでラップします。エンジンを作成し、サーフェス(内部でPTYを起動します)を作成し、それに書き込み、レンダリング状態をプルして、どの行が変更されたか、各セルに何が含まれているかを示します。#include "librio.h"rio_engine_t *engine = rio_engine_new(&config);rio_surface_t *surface = rio_surface_new(engine, &desc);// シェルにインプットを送信します。rio_surface_text(surface, "ls -la\n", 7);// 変更された行のみをプルして描画します。rio_render_state_t *state = rio_render_state_new(surface);rio_render_state_update(state);for (uint16_t line = 0; line < rio_render_state_lines(state); line++) { if (!rio_render_state_row_dirty(state, line)) continue; for (uint16_t col = 0; col < rio_render_state_columns(state); col++) { rio_cell_s cell = rio_render_state_cell(state, line, col); // `cell` を独自のレンダラーに渡します... }}rio_render_state_reset_dirty(state); これは、ネイティブのSwiftまたはCフロントエンドがセルごとに消費する正確なサーフェスです。ダーティ行のレンダリング状態は、CPUレンダリングを実用的にします。コンシューマーは、ターミナルが変更されたと指示したセルのみを再描画し、エスケープシーケンスを一切再実装することはありません。そして、クロスプラットフォームです。同じC ABIは、macOS、Linux、Windowsでビルドおよび実行され、プラットフォームのPTY(WindowsではConPTY)を介して実際のシェルを起動します。すでに本番稼働中​これは科学プロジェクトではありません。rio-vtはすでにLovableなどの企業で本番環境で使用されており、実際のターミナルワークロードを支えています。コアを独自のクレートに抽出したのは、単なるクリーンアップではなく、他の製品がRioが出荷するのと同じエンジンを構築できるようにするためでした。パフォーマンス​数字の前に注意点があります。ベンチマークはトリッキーであり、このスイートが測定しない多くの領域でrio-vtのパフォーマンスが悪いことは確かです。ワークロードは、ユーザーが私に持ち込んだ実際のプロダクションケースに基づいており、すべてのコードパスを網羅する合成ツアーではありません。例えば、libghosttyは、より大きなスクロールバック(約8〜10k行以上)やリサイズでもrio-vtを上回ると予想されますが、このスイートをRustクレートに焦点を当てることに決めて以来、ベンチマークしていません。最終的にはlibghosttyとの本格的なベンチマークを行う予定です。私はスタンドアロンベンチマークrio-vt-benchmarkを維持しており、同じワークロードでrio-vtとvt100(doyの優れたパーサー)およびalacritty_terminalを比較しています。バイトストリームの解析、画面のシリアライズ、リサイズの1つを、すべて固定の80x24で行います。以下の数字は、Apple Silicon Mac(rio-vt 0.5、vt100 0.15、alacritty_terminal 0.26)でのCriterionの中央値です。CPUと入力に依存するため、ご自身で実行してください。バイトストリームを画面に解析する(スループット、高いほど良い):Workloadrio-vtvt100alacrittywinnermixed302 MiB/s221 MiB/s254 MiB/srio-vtascii_plain835 MiB/s196 MiB/s279 MiB/srio-vt 3.0×sgr_churn235 MiB/s349 MiB/s332 MiB/svt100scroll_storm274 MiB/s101 MiB/s266 MiB/srio-vtalt_screen_redraw588 MiB/s231 MiB/s282 MiB/srio-vt 2.1×unicode_wide248 MiB/s203 MiB/s337 MiB/salacritty 画面をバイトストリームにシリアライズする(低いほど良い;rio-vtとvt100のみが画面ダンプを公開しています):Operationrio-vtvt100winnercontents_formatted (ANSI)4.3 µs18.6 µsrio-vt 4.3×contents_plain (text)3.8 µs13.9 µsrio-vt 3.7× 80x24を100x40にリサイズして元に戻す(低いほど良い):Operationrio-vtvt100alacrittywinnerresize5.0 µs7.5 µs227 µsrio-vt rio-vtはほとんどの形状でより速く解析し、特にプレーングリフ(ascii_plain)やフルスクリーン再描画(alt_screen_redraw)の作業では圧倒的な差をつけます。画面のシリアライズは数倍速く、リサイズはどちらよりもはるかに高速ですが、それでも折り返し行を再配置します(vt100は再配置をスキップするため、縮小時にコンテンツがクリップされ、alacrittyは再配置しますが、ここでは2桁遅いです)。クリーンな勝利ではありません。vt100はsgr_churnで勝ち、rio-vtのセルごとのスタイルインターニングはプレーンなセルごとのスタイルよりもコストがかかります。alacrittyはunicode_wideで勝ちます。異なるエンジン、異なるトレードオフ。だからこそベンチマークは公開されているのです。今後の展望​rio-vtはcrates.ioにあり、Rio(0.5)とバージョン管理されているため、どのRustプロジェクトでも今日から依存できます。librioはインストールするクレートではありません。各GitHubリリースには、Swift用のRioKit.xcframeworkと、C用のベアなlibrio.a + librio.hが含まれています。そのため、macOSのSwift/CパスはRustツールチェーンなしでドロップインできます。LinuxとWindowsでは、cargo build -p librioでソースからビルドします。WebAssemblyサポート。RustアプリやネイティブmacOSアプリに実際のターミナルを組み込みたいと思ったことがあるなら、