Skip to content

v0.26.0

https://github.com/ratatui/ratatui/releases/tag/v0.26.0

このリリースについては、 breaking changes を参照してください。

FOSDEM

このリリースが公開された時点で、メンテナーの1人 ( Orhun Parmaksız ) は、 FOSDEM でRatatuiについての入門的な講演を行います!講演も記録され、ライブでストリーミングされます。

イベントの詳細 here を参照してください。

お近くにお越しの際は、ぜひ Ratatui のステッカーをゲットするチャンスをお見逃しなく!

デモ: モードを破壊する

破壊モードを備えた新しいデモができました! (Ratatui の 1000 番目のコミットを祝うために作成されました)

Destroy Demo2

それを実行するには:

Terminal window
cargo run --example demo2 --features="crossterm widget-calendar"

d を押して、Destroy Modeをアクティブにして楽しんでください!

REFウィジェット実装🧩

多くのウィジェットは、状態を変更せずにレンダリングできるようになりました。

ウィジェットへの参照のために WidgetRef のtrait を実装し、その実装を不変に変更しました。これにより、ウィジェットを消費せずにレンダリングすることができます。ウィジェットをウィジェットに Frame::render_widget() に渡すことができます。また、箱入りウィジェットをレンダリングすることもできます。

注: このtrait は、機能フラグ unstable-widget-ref の後ろにゲートされています。私たちが取るアプローチは、これに対して変更される可能性があります (以下のコードが WidgetRef の代わりに Widget を使用できるようにするアプローチがあるため) 。

// this might be stored in a struct
let paragraph = Paragraph::new("Hello world!");
let [left, right] = area.split(&Layout::horizontal([20, 20]));
frame.render_widget(&paragraph, left);
frame.render_widget(&paragraph, right); // we can reuse the widget
let widgets: Vec<Box<dyn WidgetRef>> = vec![Box::new(Line::raw("hello"), Span::raw("world"))];
for widget in widgets {
widget.render_ref(area, &mut buf);
}

レイアウト: flex

Layout 内の要素の間隔を設定する新しい方法、Flex をサポートするようになりました。flexbox をベースにした Flex 列挙型を追加しました。

  • Flex::Start (新しいデフォルト)
  • Flex::Center
  • Flex::End
  • Flex::SpaceAround
  • Flex::SpaceBetween
  • Flex::Legacy (古いデフォルト)

デフォルトを Flex::Start に変更することに加えて、制約にいくつかの変更を加えました。

  1. Min(v) は、縮小するのではなく、すべての Flex モードで余分なスペースを割り当てるために拡大します (古い動作を保持する Flex::Legacy を除く)。

  2. 余分なスペースを割り当てるために拡大し、Min(v) と同等に拡大する新しい制約バリアント Fill(1) を追加しました。

制約の動作に対する重大な変更ですが、ほとんどのユーザーは、特に Min() が制約の 1 つである場合、新しい Flex::Start で同じレイアウトを確認できるはずです。ただし、古い動作が必要な場合は、Flex::Legacy を使用できます。

Layout::vertical([Length(25), Length(25)]).flex(Flex::Legacy)

また、不安定な機能 SegmentSize を削除しました。

この機能の背後にある動機と詳細については、 pull request をご覧ください。

また、Constraint-Explorer TUIを構築しました。これにより、さまざまな Flex モードで制約がどのように動作するかを比較できます。 constraint-explorer のビデオデモについては、 pull request をチェックしてください。

カラーパレット🎨

使用できる2つの真新しい色のパレット、 Material と Tailwind があります。

ratatui::style::palette::material モジュールには、Google 2014マテリアルデザインパレットが含まれています。

use ratatui::style::palette::material::BLUE_GRAY;
Line::styled("Hello", BLUE_GRAY.c500);

ratatui::style::palette::tailwind モジュールには、デフォルトのテールワインドカラーパレットが含まれています。これは、Tailwindカラーパレットに合った色のスタイリングコンポーネントに役立ちます。

use ratatui::style::palette::tailwind::SLATE;
Line::styled("Hello", SLATE.c500);

詳細については、https://m2.material.io/design/color/the-color-system.html#tools-for-picking-colorsおよびhttps://tailwindcss.com/docs/customizing-colorsを参照してください。

アライメントコンビニエンス関数🏗️

LineParagraphText に次の配置便利関数を追加しました。

  • Line::from("align on left").left_aligned();
  • Line::from("centered!").centered();
  • Line::from("align on right").right_aligned();

ParagraphText にも同じことが適用されます (例: Paragraph::new("Hello, world!").centered())。

Span 一方、次の新しい方法があります。

let span = Span::styled("Test Content", Style::new().green().italic());
// convert span to left-aligned line
let line = span.to_left_aligned_line();
// convert span to right-aligned line
let line = span.to_right_aligned_line();
// convert span to center-aligned line
let line = span.to_center_aligned_line();

パディング: 新しいコンストラクター🏗️

Padding には新しいコンストラクターがあります。

  • Padding::proportional(4);: 水平方向と垂直方向のパディングを等しくします
  • Padding::symmetric(5, 6);: 左右のパディングを定義します
  • Padding::left(3);: 左のパディングを定義します
  • Padding::right(3);: 右のパディングを定義します
  • Padding::top(3);: 上のパディングを定義します
  • Padding::bottom(3);: 下のパディングを定義します

ブロック: bordered 🧱

Block には、境界なしのブロックの作成と設定 Borders::ALL を避けるための bordered という名前の新しいコンストラクターメソッドがあります。

そのため、次のようにコードを簡素化できます。

Block::default().borders(Borders::ALL);
Block::bordered();

色: 新しいコンストラクター🏗️

Color は、 u32 値から構築できます。フォーマットは 0x00RRGGBB です。

let white = Color::from_u32(0x00FFFFFF);
let black = Color::from_u32(0x00000000);

また、 Color::Rgb 値を構築するための from_hsl メソッドも追加しました。

let color: Color = Color::from_hsl(360.0, 100.0, 100.0);
assert_eq!(color, Color::Rgb(255, 255, 255));
let color: Color = Color::from_hsl(0.0, 0.0, 0.0);
assert_eq!(color, Color::Rgb(0, 0, 0));

HSLは、色相 (0-360度) 、飽和 (0-100%) 、および軽さ (0-100%) を略し、HSL の作業はより直感的になります。たとえば、赤い色をよりオレンジ色にしたい場合は、色のホイール上の黄色に近い色の色を変えることができます (つまり、色相を増やします) 。

レイアウト: キャッシュサイズを増やする

レイアウトのデフォルトのキャッシュサイズを16から500に増やします。

これは、 ラップトップのターミナル (171+51 = 222) に列と行を追加し、適切な尺度で2倍にし、 ラウンド数になります。これにより、すべての行とすべての列のレイアウトを2回上に保存するのに十分なエントリが提供されます。これは、ほとんどのアプリに十分なはずです。

さらに必要な場合は、キャッシュサイズを Layout::init_cache() で設定できます。

this issue の関連する議論を参照してください。

レイアウト: 水平および垂直コンストラクター🏗️

Layout では、次のコンストラクタを使用して、デフォルト値を持つ垂直または水平レイアウトを作成できるようになりました。

let layout = Layout::vertical([Constraint::Length(10), Constraint::Min(5)]);
let layout = Layout::horizontal([Constraint::Length(10), Constraint::Min(5)]);

レイアウト: 制約を受け入れます

レイアウト コンストラクターは、AsRef<Constraint> だけでなく、Into<Constraint> を実装する任意の型を受け入れるようになりました。これは、レイアウトの固定サイズを指定したいが、Constraint::Length を明示的に自分で作成したくない場合に便利です。

Layout::new(Direction::Vertical, [1, 2, 3]);
Layout::horizontal([1, 2, 3]);
Layout::vertical([1, 2, 3]);
Layout::default().constraints([1, 2, 3]);

レイアウト: spacing 📏

これで、レイアウトのアイテム間に間隔を追加できるようになりました。

let layout = Layout::horizontal([Length(20), Length(20), Length(20)]).spacing(2);

rect: contains 🔲

ヒット テストを実行したい場合は、この新しいメソッドが適しています。(例: ユーザーが領域をクリックしたかどうか)

Rect::new(1, 2, 3, 4).contains(Position { x: 1, y: 2 }) // true

また、x 座標と y 座標 (列と行) を格納するための Position 構造体も追加しました。

rect: clamp 🦞

四角形を動的に移動できるようにしたいが、特定の領域に制限したい場合に便利な新しいメソッドがあります。

たとえば、これを使用して、移動できるがターミナル ウィンドウの外側には移動できないドラッグ可能なウィンドウを実装できます。

let window_area = Rect::new(state.x, state.y, 20, 20).clamp(area);
state.x = rect.x;
state.y = rect.y;

レイアウト: areas および spacers メソッド🍌

これで、より簡潔な方法で Rect を複数のサブ Rect に分割できるようになりました。

use Constraint::*;
let layout = Layout::vertical([Length(1), Min(0)]);
let [top, main] = layout.areas();
let [above, inbetwee, below] = layout.spacers();

rect: rows/colums iterators🔲

これにより、Rect の行と列を反復処理できるようになり、セルのループが簡素化されます。

let area = Rect::new(0, 0, 3, 2);
let rows: Vec<Rect> = area.rows().collect();
let columns: Vec<Rect> = area.columns().collect();

表: 制約を受け入れます

テーブル コンストラクターは、AsRef<Constraint> だけでなく、Into<Constraint> を実装する任意の型を受け入れるようになりました。これは、テーブル列の固定サイズを指定したいが、Constraint::Length を明示的に自分で作成したくない場合に便利です。

Table::new(rows, [1,2,3])
Table::default().widths([1,2,3])

表: Iteratorを受け入れます

以前は、Table::new()IntoIterator<Item=Row<'a>> を受け入れていました。引数が IntoIterator<Item: Into<Row<'a>>> に変更されました。これにより、呼び出しスコープからより柔軟な型を使用できますが、空のコンテナの呼び出しスコープでの型推論が一部壊れる可能性があります。

let table = Table::new(vec![], widths);
// becomes
let table = Table::default().widths(widths);

これは、項目が Row に変換可能なイテレータを Table に収集できるようになったことも意味します。

表: テキストをハイライトシンボル📊として受け入れます

これで、マルチラインシンボルを使用して、テーブル内のアイテムを強調表示できます。

let table = Table::new(rows, widths)
.highlight_symbol(Text::from(vec![
"".into(),
"".into(),
"".into(),
"".into(),
]));
See the demo

Made with VHS

Table は、下部に表示される行を設定するための footer メソッドがあるようになりました。

let footer = Row::new(vec![
Cell::from("Footer Cell 1"),
Cell::from("Footer Cell 2"),
]);
let table = Table::default().footer(footer);

それに加えて、 Row の新しい top_margin メソッドがあります。

let row = Row::default().top_margin(1);

ウィジェット実装🧩

LineSpanWidget を実装するようになりました。つまり、他のウィジェットの子として使用できます。

buffer.set_line() を呼び出す代わりに、Line::render() を使用してレンダリングすることもできます。

frame.render_widget(Line::raw("Hello, world!"), area);
// or
Line::raw("Hello, world!").render(frame, area);

Span にも同じことが当てはまり、 buffer.set_span() を呼び出すのではなく、 Span::render() を使用してレンダリングできます。

行: styled 🎨

以前は、 Line のスタイルは、ラインを構成する Span に保存されていました。これで、 Line 自体には style フィールドがあり、 Line::styled メソッドで設定できます。

let style = Style::new().yellow();
let content = "Hello, world!";
let line = Line::styled(content, style);

コンストラクタの代わりに構造体初期化子を使用して Line を作成するコードは、追加されたフィールドが原因でコンパイルに失敗します。これは、フィールド リストに ..Default::default() を追加するか、コンストラクタ メソッド (Line::styled()Line::raw()) または変換メソッド (Line::from()) を使用することで簡単に修正できます。

let line = Line {
spans: vec!["".into()],
alignment: Alignment::Left,
..Default::default()
};

スタイル: 🎨に受け入れます

すべてのスタイル関連メソッドは、Style の代わりに S: Into<Style> を受け入れるようになりました。ColorModifierInto<Style> を実装しているため、より人間工学的な使用が可能になります。例:

Line::styled("hello", Style::new().red());
Line::styled("world", Style::new().bold());
// can now be simplified to
Line::styled("hello", Color::Red);
Line::styled("world", Modifier::BOLD);

つまり、Into<Style> を実装するあいまいな型をすでに渡している場合は、.into() 呼び出しを削除する必要があります。

タブ: Line のiteratorを受け入れます📑

以前は Tabs::newVec を必要としていましたが、 Into<Line> を実装するアイテムタイプで IntoIterator を実装するオブジェクトを受け入れることができます。

Tabs::new() への呼び出しは、iteratorから引数が収集されたものでコンパイルされなくなります。

たとえば、 .collect() の返品タイプが Vec<_> であると推測できなくなるため、 Tabs::new(["a","b"].into_iter().collect()) はコンパイルされなくなります。

let table = Tabs::new((0.3).map(|i| format!("{i}")).collect());
// becomes
let table = Tabs::new((0.3).map(|i| format!("{i}")));

新しいボーダーセット🔲

McGugan ボーダーセットを追加しました。これにより、境界線が狭くなります。

McGugan Boxテクニックに基づいた広い境界セット:

▁▁▁▁▁▁▁
▏xxxxx▕
▏xxxxx▕
▔▔▔▔▔▔▔

McGugan Boxテクニックに基づいた背の高いボーダーセット:

▕▔▔▏
▕xx▏
▕xx▏
▕▁▁▏

ターミナル: フレームカウント🔢

現在のフレームカウントを取得できます!

let mut frame = terminal.get_frame();
let current_count = frame.count();
println!("Current frame count: {}", current_count);

このカウントは、ディスプレイの状態が時間とともに変化する動的なコンテンツまたはアニメーションを扱う場合に特に役立ちます。フレームカウントを追跡することにより、開発者は更新またはレンダリングプロセスでコンテンツの変更を同期させることができます。

バッファ: SSO🐜

buffer::Cell のテキスト バッファに SSO (小さな文字列の最適化) 手法を適用するようになりました。つまり、Cell::symbol フィールドを格納するために String ではなく CompactString を使用します。これにより、実行時のメモリ割り当てのサイズが削減されます。

関連する議論 here を参照してください。

他の💼

  • Constraint::ProportionalConstraint::Fill に変更します ( #880 )
  • rect->サイズの変換方法 ( #789 )
  • Implement Display for Text , Line , Span ( #826 )
  • Support de/serialization of TableState, ListState, and ScrollbarState via serde feature
  • Implement FromIterator for Row ( #755 )
  • TERMWIZスタイルに From を追加 ( #726 )
  • Text ( #807 ) にスタイルとアライメントを追加します
  • ListListItem にイテレーターを収集 ( #757 )
  • patch_style および reset_style チェーン可能 ( #754 ) を作成します