Skip to content

Commit

Permalink
feat(docs): improve spawn-vim docs by emphasizing spawning vim logic,…
Browse files Browse the repository at this point in the history
… fix md link in index.md

Signed-off-by: Deep Panchal <[email protected]>
  • Loading branch information
deepanchal committed Jul 13, 2024
1 parent 5eaf697 commit 7be0016
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 69 deletions.
2 changes: 1 addition & 1 deletion src/content/docs/recipes/apps/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ This section covers recipes for developing applications:
- [Setup Panic Hooks](./panic-hooks/)
- [Use Better Panic](./better-panic/)
- [Migrate from TUI-rs](./migrate-from-tui-rs/)
- [Spawn Vim][./spawn-vim/]
- [Spawn Vim](./spawn-vim/)
123 changes: 55 additions & 68 deletions src/content/docs/recipes/apps/spawn-vim.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,101 +5,88 @@ sidebar:
label: Spawn External Editor (Vim)
---

This tutorial demonstrates how to spawn an external editor like Vim from a `ratatui` application.
We'll start with a simple
[hello-world-ratatui](https://github.com/ratatui-org/ratatui-website/tree/main/code/hello-world-tutorial)
example.
In this recipe, we will explore how to spawn an external editor (Vim) from within the TUI app. This
example demonstrates how to temporarily exit the TUI, run an external command, and then return back
to our TUI app.

## Add imports
Full code:

Let's start by adding imports

```rust
{{ #include @code/how-to-spawn-vim/src/main.rs:imports }}
```rust collapsed title="main.rs (click to expand)"
{{ #include @code/how-to-spawn-vim/src/main.rs }}
```

## Add actions
## Setup

Next, we define actions that our application will handle:
First, let's look at the main function and the event handling logic:

```rust
```rust title="main.rs"
{{ #include @code/how-to-spawn-vim/src/main.rs:action_enum }}
```

## Setup

Now, let's setup our main function and initialize the terminal:
{{ #include @code/how-to-spawn-vim/src/main.rs:main }}

```rust
fn main() -> Result<()> {
{{ #include @code/how-to-spawn-vim/src/main.rs:setup }}
}
{{ #include @code/how-to-spawn-vim/src/main.rs:handle-events }}
```

Within our main function loop, we need to draw the UI and handle events. We'll draw a simple message
and handle key events for quitting the application or spawning Vim:

```rust
fn main() -> Result<()> {
// terminal setup ...

loop {
{{ #include @code/how-to-spawn-vim/src/main.rs:draw }}
}
}
```
In the `main` function, we initialize the terminal and enter a loop where we draw the UI and handle
events. The `handle_events` function listens for key events and returns an `Action` based on the key
pressed.

## Handle events
## Spawning vim

We'll then handle the events that occur. On pressing 'q', the application will quit; on pressing
'e', the application will spawn Vim.
Now, lets define the function `run_editor` function attached to `Action::EditFile` action.

In the event handling loop, add logic to handle the EditFile action. This includes:
```rust title="main.rs"
{{ #include @code/how-to-spawn-vim/src/main.rs:run_editor }}
```

1. Exiting the alternate screen mode.
2. Disabling raw input mode.
3. Spawning Vim to edit /tmp/a.txt.
4. Re-entering the alternate screen mode.
5. Re-enabling raw input mode.
6. Reinitializing the ratatui terminal.
To spawn Vim from our TUI app, we first need to relinquish control of input and output, allowing Vim
to have full control over the terminal.

```rust
fn main() -> Result<()> {
// terminal setup ...
The `run_editor` function handles the logic for spawning vim. First, we leave the alternate screen
and disable raw mode to restore terminal to it's original state. This part is similar to what
`restore_terminal` function does in the
[full code](https://github.com/ratatui-org/ratatui-website/tree/main/code/how-to-spawn-vim/src/main.rs).
Next, we spawn a child process with `Command::new("vim").arg("/tmp/a.txt").status()` which launches
`vim` to edit the given file. At this point, we have given up control of our TUI app to vim. Our TUI
app will now wait for the exit status of the child process (i.e., Vim). Once the user exits Vim, our
TUI app regains control over the terminal by re-entering alternate screen and enabling raw mode.
Lastly, we clear the terminal to ensure the TUI is displayed correctly.

loop {
// terminal draw ...
:::note

{{ #include @code/how-to-spawn-vim/src/main.rs:handle-events }}
}
}
```
Before running another application from your app, you must relinquish control of input and output,
allowing the other app to function correctly.

## Restore terminal
In the example above, we use a simple event-handling setup. However, if you are using advanced
setups like [component template](https://github.com/ratatui-org/templates), you will need to pause
input events before spawning an external process like Vim. Otherwise, Vim won't have full control
over keybindings and it won't work properly.

After exiting the loop, we need to restore the terminal to its original state:
Using the
[`tui` module](https://github.com/ratatui-org/templates/blob/5e823efc871107345d59e5deff9284235c1f0bbc/component/template/src/tui.rs)
of the component template, you can do something like this to pause and resume event handlers:

```rust
fn main() -> Result<()> {
// terminal setup ...

// loop ...

{{ #include @code/how-to-spawn-vim/src/main.rs:restore }}
Action::EditFile => {
tui.exit()?;
let cmd = String::from("vim");
let cmd_args = vec!["/tmp/a.txt".into()];
let status = std::process::Command::new(&command).args(&args).status()?;
if !status.success() {
eprintln!("\nCommand failed with status: {}", status);
}
tui.enter()?;
tui.terminal.clear();
}
```

## Final code

Here is the complete code:
:::

```rust
{{ #include @code/how-to-spawn-vim/src/main.rs }}
```
## Running code

This completes the tutorial. Running this program will display "Hello ratatui! (press 'q' to quit,
'e' to edit a file)" in the terminal. Pressing 'e' will exit to spawn Vim for editing a temporary
file and then return to the ratatui application after Vim is closed.
Running this program will display "Hello ratatui! (press 'q' to quit, 'e' to edit a file)" in the
terminal. Pressing 'e' will spawn a child process to spawn Vim for editing a temporary file and then
return to the ratatui application after Vim is closed.

Feel free to adapt this example to use other editors like `nvim`, `nano`, etc., by changing the
command in the `Action::EditFile` arm.
Expand Down

0 comments on commit 7be0016

Please sign in to comment.