editor: Fix panic in text_layout_details pre layout (#55816)
Fixes a panic at `Editor::text_layout_details` when called against an editor whose element has never been laid out (i.e., `set_style` has never been called, so the cached `style` is still `None`). We've seen this crash once through a helix motion. The exact production sequence isn't clear — for the editor to receive a vim action without ever having been drawn, the active item would have to have changed inside the same update tick that ends with the deferred `search_submit`, which is narrow but not impossible (since it's dispatched by the workspace, not the editor). Release Notes: - Fixed a rare panic when invoking helix motions on an editor that had not yet been laid out.
This commit is contained in:
1 parent
26b9e07fa8
commit
de765f98bb
2 files changed
+56
-1
No files matched your search
@@ -5985,7 +5985,7 @@ impl Editor {
|
||||
pub fn text_layout_details(&self, window: &mut Window, cx: &mut App) -> TextLayoutDetails {
|
||||
TextLayoutDetails {
|
||||
text_system: window.text_system().clone(),
|
||||
editor_style: self.style.clone().unwrap(),
|
||||
editor_style: self.style.clone().unwrap_or_else(|| self.create_style(cx)),
|
||||
rem_size: window.rem_size(),
|
||||
scroll_anchor: self.scroll_manager.shared_scroll_anchor(cx),
|
||||
visible_rows: self.visible_line_count(),
|
||||
|
||||
@@ -2960,6 +2960,61 @@ mod test {
|
||||
cx.assert_state("«ˇone» two three", Mode::HelixSelect);
|
||||
}
|
||||
|
||||
// Regression test for ZED-758: helix motions called
|
||||
// `Editor::text_layout_details` on an editor whose `style` had never
|
||||
// been set, panicking on `unwrap()`.
|
||||
#[gpui::test]
|
||||
async fn test_helix_motion_on_unrendered_editor(cx: &mut gpui::TestAppContext) {
|
||||
use editor::{Editor, EditorMode, SelectionEffects};
|
||||
use multi_buffer::{MultiBuffer, MultiBufferOffset};
|
||||
|
||||
VimTestContext::init(cx);
|
||||
cx.update(|cx| {
|
||||
VimTestContext::init_keybindings(true, cx);
|
||||
SettingsStore::update_global(cx, |store, cx| {
|
||||
store.update_user_settings(cx, |s| {
|
||||
s.vim_mode = Some(true);
|
||||
s.helix_mode = Some(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
let cx = cx.add_empty_window();
|
||||
|
||||
let editor = cx.update(|window, cx| {
|
||||
use gpui::AppContext as _;
|
||||
let buffer = MultiBuffer::build_simple("one two three", cx);
|
||||
cx.new(|cx| {
|
||||
let mut editor = Editor::new(EditorMode::full(), buffer, None, window, cx);
|
||||
editor.change_selections(SelectionEffects::no_scroll(), window, cx, |s| {
|
||||
s.select_ranges([MultiBufferOffset(4)..MultiBufferOffset(4)])
|
||||
});
|
||||
editor
|
||||
})
|
||||
});
|
||||
|
||||
let vim = editor
|
||||
.read_with(cx, |editor, _| editor.addon::<VimAddon>().cloned())
|
||||
.expect("VimAddon should be auto-attached to new editors when vim mode is enabled");
|
||||
|
||||
cx.update(|window, cx| {
|
||||
vim.entity.update(cx, |vim, cx| {
|
||||
vim.switch_mode(Mode::HelixNormal, true, window, cx);
|
||||
vim.helix_move_and_collapse(crate::motion::Motion::Left, None, window, cx);
|
||||
});
|
||||
});
|
||||
|
||||
let cursor_offset = cx.update(|_, cx| {
|
||||
editor.update(cx, |editor, cx| {
|
||||
editor
|
||||
.selections
|
||||
.newest::<MultiBufferOffset>(&editor.display_snapshot(cx))
|
||||
.head()
|
||||
})
|
||||
});
|
||||
assert_eq!(cursor_offset, MultiBufferOffset(3));
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_helix_select_regex(cx: &mut gpui::TestAppContext) {
|
||||
let mut cx = VimTestContext::new(cx, true).await;
|
||||
|
||||
Reference in new issue
Block a user