Skip to content

Commit

Permalink
Fix garbage events from vim
Browse files Browse the repository at this point in the history
Vim dumps out some garbage events on exit, which causes strange behavior in Slumber.

Closes #351
  • Loading branch information
LucasPickering committed Sep 1, 2024
1 parent 4ab1ee4 commit 48b851c
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Here's the full list of changes:
- E.g. F5 will now refresh the collection while a text box is in focus
- Redraw TUI when terminal is resized
- Clamp text window scroll state when window is resized or text changes
- Fix extraneous input events when exiting Vim [#351](https://github.com/LucasPickering/slumber/issues/351)

## [1.8.1] - 2024-08-11

Expand Down
23 changes: 17 additions & 6 deletions crates/slumber_tui/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ mod view;
use crate::{
context::TuiContext,
message::{Message, MessageSender, RequestConfig},
util::{get_editor_command, save_file, signals, ResultReported},
util::{
clear_event_buffer, get_editor_command, save_file, signals,
ResultReported,
},
view::{PreviewPrompter, RequestState, View},
};
use anyhow::{anyhow, Context};
Expand All @@ -29,7 +32,7 @@ use crossterm::{
},
terminal::{EnterAlternateScreen, LeaveAlternateScreen},
};
use futures::{Future, StreamExt};
use futures::StreamExt;
use notify::{event::ModifyKind, RecursiveMode, Watcher};
use ratatui::{prelude::CrosstermBackend, Terminal};
use slumber_config::{Action, Config};
Expand All @@ -40,6 +43,7 @@ use slumber_core::{
template::{Prompter, Template, TemplateChunk, TemplateContext},
};
use std::{
future::Future,
io::{self, Stdout},
ops::Deref,
path::{Path, PathBuf},
Expand Down Expand Up @@ -418,11 +422,18 @@ impl Tui {
self.terminal.draw(|frame| {
frame.render_widget("Waiting for editor to close...", frame.area());
})?;

let mut stdout = io::stdout();
crossterm::execute!(stdout, LeaveAlternateScreen)?;
command.status().context(error_context)?;
// If the editor was terminal-based it probably dropped us out of the
// alternate screen when it closed, so get back in there. This is
// idempotent so no harm in doing it
crossterm::execute!(io::stdout(), EnterAlternateScreen)?;
// Some editors *cough* vim *cough* dump garbage to the event buffer on
// exit. I've never figured out what actually causes it, but a simple
// solution is to dump all events in the buffer before returning to
// Slumber. It's possible we lose some real user input here (e.g. if
// other events were queued behind the event to open the editor).
clear_event_buffer();
crossterm::execute!(stdout, EnterAlternateScreen)?;

// Redraw immediately. The main loop will probably be in the tick
// timeout when we go back to it, so that adds a 250ms delay to
// redrawing the screen that we want to skip.
Expand Down
9 changes: 9 additions & 0 deletions crates/slumber_tui/src/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
view::Confirm,
};
use anyhow::Context;
use crossterm::event;
use editor_command::EditorBuilder;
use futures::{future, FutureExt};
use slumber_core::{
Expand All @@ -15,6 +16,7 @@ use std::{
ops::Deref,
path::{Path, PathBuf},
process::Command,
time::Duration,
};
use tokio::{fs::OpenOptions, io::AsyncWriteExt, sync::oneshot};
use tracing::{debug, error, info, warn};
Expand Down Expand Up @@ -45,6 +47,13 @@ where
}
}

/// Clear all input events in the terminal event buffer
pub fn clear_event_buffer() {
while let Ok(true) = event::poll(Duration::from_millis(0)) {
let _ = event::read();
}
}

/// Listen for any exit signals, and return `Ok(())` when any signal is
/// received. This can only fail during initialization.
#[cfg(unix)]
Expand Down

0 comments on commit 48b851c

Please sign in to comment.