fix: crash after open_commit_editor on Windows

Use a dedicated OpenCommitEditor event, keep the commit popup visible,
and disable raw mode while the external editor runs so the terminal is
restored before committing.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wuyangfan 2026-05-17 16:54:28 +08:00
parent 8619c07f3f
commit 6211758bd2
4 changed files with 43 additions and 17 deletions

View file

@ -119,6 +119,7 @@ pub struct App {
// "Flags"
requires_redraw: Cell<bool>,
file_to_open: Option<String>,
open_commit_editor: bool,
}
pub struct Environment {
@ -244,6 +245,7 @@ impl App {
key_config: env.key_config,
requires_redraw: Cell::new(false),
file_to_open: None,
open_commit_editor: false,
repo: env.repo,
repo_path_text,
popup_stack: PopupStack::default(),
@ -371,17 +373,19 @@ impl App {
} else if let InputEvent::State(polling_state) = ev {
self.external_editor_popup.hide();
if matches!(polling_state, InputState::Paused) {
let result =
if let Some(path) = self.file_to_open.take() {
ExternalEditorPopup::open_file_in_editor(
&self.repo.borrow(),
Path::new(&path),
)
} else {
let changes =
self.status_tab.get_files_changes()?;
self.commit_popup.show_editor(changes)
};
let result = if self.open_commit_editor {
self.open_commit_editor = false;
let changes =
self.status_tab.get_files_changes()?;
self.commit_popup.show_editor(changes)
} else if let Some(path) = self.file_to_open.take() {
ExternalEditorPopup::open_file_in_editor(
&self.repo.borrow(),
Path::new(&path),
)
} else {
Ok(())
};
if let Err(e) = result {
let msg =
@ -816,11 +820,19 @@ impl App {
}
}
InternalEvent::OpenExternalEditor(path) => {
self.open_commit_editor = false;
self.input.set_polling(false);
self.external_editor_popup.show()?;
self.file_to_open = path;
flags.insert(NeedsUpdate::COMMANDS);
}
InternalEvent::OpenCommitEditor => {
self.file_to_open = None;
self.open_commit_editor = true;
self.input.set_polling(false);
self.external_editor_popup.show()?;
flags.insert(NeedsUpdate::COMMANDS);
}
InternalEvent::Push(branch, push_type, force, delete) => {
self.push_popup
.push(branch, push_type, force, delete)?;

View file

@ -586,10 +586,7 @@ impl Component for CommitPopup {
e,
self.key_config.keys.open_commit_editor,
) {
self.queue.push(
InternalEvent::OpenExternalEditor(None),
);
self.hide();
self.queue.push(InternalEvent::OpenCommitEditor);
true
} else if key_match(
e,

View file

@ -14,7 +14,10 @@ use asyncgit::sync::{
};
use crossterm::{
event::Event,
terminal::{EnterAlternateScreen, LeaveAlternateScreen},
terminal::{
disable_raw_mode, enable_raw_mode, is_raw_mode_enabled,
EnterAlternateScreen, LeaveAlternateScreen,
},
ExecutableCommand,
};
use ratatui::{
@ -61,9 +64,21 @@ impl ExternalEditorPopup {
bail!("file not found: {path:?}");
}
let raw_mode_enabled = is_raw_mode_enabled()?;
if raw_mode_enabled {
disable_raw_mode()?;
}
io::stdout().execute(LeaveAlternateScreen)?;
defer! {
io::stdout().execute(EnterAlternateScreen).expect("reset terminal");
if let Err(e) = io::stdout().execute(EnterAlternateScreen) {
log::error!("failed to re-enter alternate screen: {e}");
}
if raw_mode_enabled {
if let Err(e) = enable_raw_mode() {
log::error!("failed to re-enable raw mode: {e}");
}
}
}
let environment_options = ["GIT_EDITOR", "VISUAL", "EDITOR"];

View file

@ -123,6 +123,8 @@ pub enum InternalEvent {
///
OpenExternalEditor(Option<String>),
///
OpenCommitEditor,
///
Push(String, PushType, bool, bool),
///
Pull(String),