Spawn External Editor (Vim)
このレシピでは、TUI アプリ内から外部エディター (Vim) を起動する方法を説明します。この例では、TUI を一時的に終了し、外部コマンドを実行してから、TUI アプリに戻る方法を示します。
完全なコード:
main.rs (click to expand)
use ratatui::{ backend::CrosstermBackend, crossterm::{ event::{self, Event, KeyCode, KeyEventKind}, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, ExecutableCommand, }, widgets::Paragraph, DefaultTerminal, Frame,};use std::io::{stdout, Result};use std::process::Command;
type Terminal = ratatui::Terminal<CrosstermBackend<std::io::Stdout>>;
enum Action { EditFile, Quit, None,}
fn main() -> Result<()> { let terminal = ratatui::init(); let app_result = run(terminal); ratatui::restore(); app_result}
fn run(mut terminal: DefaultTerminal) -> Result<()> { loop { terminal.draw(draw)?; match handle_events()? { Action::EditFile => run_editor(&mut terminal)?, Action::Quit => break, Action::None => {} } } Ok(())}
fn handle_events() -> Result<Action> { if !event::poll(std::time::Duration::from_millis(16))? { return Ok(Action::None); } match event::read()? { Event::Key(key) if key.kind == KeyEventKind::Press => match key.code { KeyCode::Char('q') => Ok(Action::Quit), KeyCode::Char('e') => Ok(Action::EditFile), _ => Ok(Action::None), }, _ => Ok(Action::None), }}
fn run_editor(terminal: &mut Terminal) -> Result<()> { stdout().execute(LeaveAlternateScreen)?; disable_raw_mode()?; Command::new("vim").arg("/tmp/a.txt").status()?; stdout().execute(EnterAlternateScreen)?; enable_raw_mode()?; terminal.clear()?; Ok(())}
fn draw(frame: &mut Frame) { frame.render_widget( Paragraph::new("Hello ratatui! (press 'q' to quit, 'e' to edit a file)"), frame.area(), );}
設定
まず、メイン関数とイベント処理ロジックを見てみましょう。
enum Action { EditFile, Quit, None,}
fn main() -> Result<()> { let terminal = ratatui::init(); let app_result = run(terminal); ratatui::restore(); app_result}
fn run(mut terminal: DefaultTerminal) -> Result<()> { loop { terminal.draw(draw)?; match handle_events()? { Action::EditFile => run_editor(&mut terminal)?, Action::Quit => break, Action::None => {} } } Ok(())}
fn handle_events() -> Result<Action> { if !event::poll(std::time::Duration::from_millis(16))? { return Ok(Action::None); } match event::read()? { Event::Key(key) if key.kind == KeyEventKind::Press => match key.code { KeyCode::Char('q') => Ok(Action::Quit), KeyCode::Char('e') => Ok(Action::EditFile), _ => Ok(Action::None), }, _ => Ok(Action::None), }}
main
関数でターミナルを初期化した後、run
関数でループに入り、UI を描画してイベントを処理します。handle_events
関数はキー イベントをリッスンし、押されたキーに基づいて Action
を返します。ここでは、次のセクションで定義する Action::EditFile
で run_editor
関数を呼び出しています。
Spawning Vim
次に、 Action::EditFile
アクションに添付されている関数 run_editor
機能を定義しましょう。
fn run_editor(terminal: &mut Terminal) -> Result<()> { stdout().execute(LeaveAlternateScreen)?; disable_raw_mode()?; Command::new("vim").arg("/tmp/a.txt").status()?; stdout().execute(EnterAlternateScreen)?; enable_raw_mode()?; terminal.clear()?; Ok(())}
TUIアプリからVIMを生成するには、最初に入力と出力の制御を放棄し、VIMがターミナルを完全に制御できるようにする必要があります。
run_editor
関数は、vim を起動するロジックを処理します。まず、代替画面を終了し、raw モードを無効にして、ターミナルを元の状態に戻します。この部分は、main
関数の ratatui::restore
関数の動作に似ています。次に、Command::new("vim").arg("/tmp/a.txt").status()
を使用して子プロセスを起動し、指定されたファイルを編集するために vim
を起動します。この時点で、TUI アプリの制御は vim に委ねられています。TUI アプリは、子プロセスの終了ステータスを待機します。ユーザーが Vim を終了すると、TUI アプリは代替画面に再度入り、raw モードを有効にして、ターミナルの制御を取り戻します。最後に、TUI が正しく表示されるようにターミナルをクリアします。
実行コード
このプログラムを実行すると、ターミナルに「hello ratatui! ( ‘q’」、「e」を終了するには、「e」を終了します) 」をターミナルに表示します。「e」を押すと、子のプロセスが生成され、一時ファイルを編集するためにVIMを生成し、VIMが閉じた後にRATATUIアプリケーションに戻ります。
この例を自由に調整して、 Action::EditFile
armのコマンドを変更することにより、 nvim
、 nano
などの他のエディターを使用してください。