Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add section on how to spawn vim from a ratatui application #406

Open
kdheepak opened this issue Jan 29, 2024 · 11 comments
Open

Add section on how to spawn vim from a ratatui application #406

kdheepak opened this issue Jan 29, 2024 · 11 comments
Labels
enhancement New feature or request good first issue Good for newcomers

Comments

@kdheepak
Copy link
Contributor

  • You need to disable_raw_mode and exit alternate screen
  • You need to pause the event loop (if you have one) that handles any key or mouse events
  • You can then spawn vim
  • Once vim returns after wait(), you'll need to resume the event loop (if you have one)
  • You'll need to enable_raw_mode and enter alternate screen again.

Example of how to do this with an async event loop:

https://github.com/ratatui-org/templates/blob/b75771463c00088b75e90986979c60720d024bbf/component/template/src/tui.rs#L171-L198

@kdheepak kdheepak added enhancement New feature or request good first issue Good for newcomers labels Jan 29, 2024
@Valentin271
Copy link
Member

I believe this should be about the same for any other TUI: lazygit, yazi, even bash.

Also one important thing to note, this is about spawning a program and gaining back control. Which is different (and somewhat harder) than spawning a program on end.

Otherwise +1 for this.

@kdheepak
Copy link
Contributor Author

Related: kdheepak/taskwarrior-tui#46

orhun added a commit to orhun/rattler-build that referenced this issue Mar 16, 2024
wolfv pushed a commit to prefix-dev/rattler-build that referenced this issue Mar 20, 2024
* feat: create a TUI
* refactor: restructure library for accommodating TUI needs
* feat(tui): build package when enter is pressed
* fix: remove the application name
* fix: initialize logger for non-tui subcommands
* refactor: offload spinner handling to throbber-widgets-tui widget
* feat: use tail behavior for logs
* refactor: apply clippy suggestions
* feat: support mouse scrolling
* feat: support mouse clicks for starting build
* refactor: add tui feature
* fix: update import
* chore: update Cargo.lock
* refactor: use build output in TUI
* chore: add new line to build variant logs
* chore: panic on resolving packages
* refactor: fix selecting multiple packages
* refactor: create build directories before build
* refactor: use events while resolving packages
* refactor: simplify setting up the directories
* chore: remove timestamp from TUI logs
* fix: disable building packages at the same time
* fix: fix the scrollbar position for new lines
* refactor: use a single package for multiple outputs
* fix: fix scroll issues
* style: make TUI prettier
* feat: handle build errors in TUI
* feat: add key bindings for the TUI
* feat: support horizontal scrolling in TUI
* chore: add extra space for logs just to be safe
* feat: supporte editing recipe via TUI
* refactor: apply clippy suggestions
* refactor: use the recipe path for build output
* refactor: rename tui util module to utils
* fix: fix switching to input mode
* fix: cancel the event loop when launching editor (ratatui/ratatui-website#406)
* chore: implement Debug for BuildOutput
* feat: process build outputs separately for TUI
* feat: support building subpackages
* chore: log the invalid command
* fix: fix the package selection in TUI
* style: use package identifier in the TUI list
* style: render the package identifier when there is enough space
* docs: add rattler-build-tui documentation
* docs: fix admonition syntax
* docs: update key bindings style
* docs: move TUI docs to website
* docs: update wording
joshka pushed a commit that referenced this issue Jun 4, 2024
* test(span): add some tests for "Span"

* feat(span): replace all "From<*>" with one "From<Into<Cow>>>"
@deepanchal
Copy link
Contributor

deepanchal commented Jun 30, 2024

I got it to launch vim on newly generated test app (cargo generate ratatui-org/templates) with component template with the following changes

diff --git a/src/action.rs b/src/action.rs
index f422a62..ee157c2 100644
--- a/src/action.rs
+++ b/src/action.rs
@@ -17,4 +17,5 @@ pub enum Action {
   Refresh,
   Error(String),
   Help,
+  EditFile,
 }
diff --git a/src/app.rs b/src/app.rs
index e528d05..c378c00 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -126,6 +126,17 @@ impl App {
               }
             })?;
           },
+          Action::EditFile => {
+            tui.exit()?;
+            let status = std::process::Command::new("vim").arg("/tmp/a.txt").status()?;
+            if status.success() {
+              log::info!("Successfully launched vim");
+            } else {
+              log::error!("Failed to launch vim");
+            }
+            tui = tui::Tui::new()?.tick_rate(self.tick_rate).frame_rate(self.frame_rate);
+            tui.enter()?;
+          },
           _ => {},
         }
         for component in self.components.iter_mut() {
diff --git a/src/components/home.rs b/src/components/home.rs
index a1e9cc6..f1fd170 100644
--- a/src/components/home.rs
+++ b/src/components/home.rs
@@ -35,6 +35,13 @@ impl Component for Home {
     Ok(())
   }
 
+  fn handle_key_events(&mut self, key: KeyEvent) -> Result<Option<Action>> {
+    match key.code {
+      KeyCode::Char('v') => Ok(Some(Action::EditFile)),
+      _ => Ok(None),
+    }
+  }
+
   fn update(&mut self, action: Action) -> Result<Option<Action>> {
     match action {
       Action::Tick => {
@@ -45,7 +52,7 @@ impl Component for Home {
   }
 
   fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()> {
-    f.render_widget(Paragraph::new("hello world"), area);
+    f.render_widget(Paragraph::new("Hello! Press 'v' to launch vim"), area);
     Ok(())
   }
 }

@deepanchal
Copy link
Contributor

deepanchal commented Jul 1, 2024

I would like to contribute by adding this example (how-to-spawn-vim) to the repo. I will open a PR soon

@deepanchal
Copy link
Contributor

I have created a PR with basic example on how to spawn vim here #651

@LucasPickering
Copy link
Contributor

I wrote a crate called editor-command that would be tangentially helpful here. It doesn't do anything related to opening vim specifically, but it makes it easier to let the user customize the editor they want to open via the common VISUAL and EDITOR env variables, as well as configurable other sources.

Not shooting for self-promotion here, I just thought this might be helpful for readers of this page if you want to include it :)

@deepanchal
Copy link
Contributor

@LucasPickering Thanks for suggestion :)
I am already mentioning a similar looking crate called edit in the tips section at the end of spawn vim docs in my PR. Could you please verify if both libraries are trying to achieve the same functionality? After briefly looking through both libraries code, I think that editor-command crate gives you a low level control by returning Command while edit crate provides a high level interface to open editor and get edited content back.

Here are the changes I was planning on adding to the PR

diff --git a/src/content/docs/recipes/apps/spawn-vim.md b/src/content/docs/recipes/apps/spawn-vim.md
index eb86861..e2c82aa 100644
--- a/src/content/docs/recipes/apps/spawn-vim.md
+++ b/src/content/docs/recipes/apps/spawn-vim.md
@@ -105,7 +105,9 @@ command in the `Action::EditFile` arm.
 
 If you prefer to launch the user-specified `$EDITOR` and retrieve the buffer (edited content) back
 into your application, you can use the [`edit`](https://crates.io/crates/edit) crate. This can be
-particularly useful if you need to capture the changes made by the user in the editor.
+particularly useful if you need to capture the changes made by the user in the editor. There's also
+[`editor-command`](https://docs.rs/editor-command/latest/editor_command) crate if you want more
+control over launching / overriding editors based on `VISUAL` or `EDITOR` environment variables.
 
 Alternatively, you may use the [`edtui`](https://github.com/preiter93/edtui) crate from ratatui's
 ecosystem, which provides text editor widget inspired by vim.

If these changes look good to you, I will add these changes to the PR :)

@LucasPickering
Copy link
Contributor

@deepanchal Yes, it looks like both libraries hand the same end goal. I searched for a library like edit before creating editor-command but didn't find it. Some key differences I noticed between the two:

  • Like you said, editor-command returns the Command rather than executing it yourself, which gives you more control over it
    • Particularly, it means you can easily execute the editor async using tokio's From impl
  • editor-command allows you to provide a high-priority override, if you want to support a config field in your app that overrides the env vars
  • edit tries to make common editors more convenient by hardcoding a list of them

In general I think it's fair to say editor-command gives lower level control at the cost of some convenience. You change looks good to me!

@deepanchal
Copy link
Contributor

Changes are live 🎉
https://ratatui.rs/recipes/apps/spawn-vim

@micakce
Copy link

micakce commented Sep 19, 2024

How do you do so vim get all the input? In my case it seems intermittent, as if the input of the keyboard was divided between the underlying tool running and the open editor, almost half of the key strokes don't register on vim.

@kdheepak
Copy link
Contributor Author

You need to pause the event handler in your rust ratatui tui application before you spawn vim and you need to restart your event handler after vim returns. If you don't do that, key strokes may not register properly in vim.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request good first issue Good for newcomers
Projects
None yet
Development

No branches or pull requests

5 participants