Co-authored-by: dinocosta <dinojoaocosta@gmail.com>
This commit is contained in:
Conrad Irwin 2025-08-12 11:41:22 -06:00
parent 9471ab9949
commit cb2ca572e4
4 changed files with 90 additions and 116 deletions

View file

@ -225,7 +225,7 @@ pub struct CompletionsMenu {
scroll_handle: UniformListScrollHandle,
// The `ScrollHandle` used on the Markdown documentation rendered on the
// side of the completions menu.
pub(crate) scroll_handle_aside: ScrollHandle,
pub scroll_handle_aside: ScrollHandle,
resolve_completions: bool,
show_completion_documentation: bool,
last_rendered_range: Rc<RefCell<Option<Range<usize>>>>,

View file

@ -24071,119 +24071,6 @@ async fn test_newline_replacement_in_single_line(cx: &mut TestAppContext) {
});
}
#[gpui::test]
async fn test_completion_menu_scroll_aside(cx: &mut TestAppContext) {
init_test(cx, |_| {});
// In order to be able to test the shortcuts that should allow the user to
// scroll the aside content of the completions menu, we first need to load
// the keymap file, otherwise simulating the keystrokes will not actually
// dispatching the necessary action.
cx.update(|cx| {
let default_key_bindings = settings::KeymapFile::load_asset_allow_partial_failure(
"keymaps/default-macos.json",
cx,
)
.expect("Should be able to load deafult MacOS Keymap");
cx.bind_keys(default_key_bindings);
});
// Setup the completion to be provided by the LSP so we can set the
// completion item's documentation with a string long enough to overflow the
// assigned vertical space.
let mut cx = EditorLspTestContext::new_rust(
lsp::ServerCapabilities {
completion_provider: Some(lsp::CompletionOptions {
trigger_characters: Some(vec![".".to_string()]),
..Default::default()
}),
..Default::default()
},
cx,
)
.await;
cx.lsp
.set_request_handler::<lsp::request::Completion, _, _>(move |_, _| async move {
Ok(Some(lsp::CompletionResponse::Array(vec![
lsp::CompletionItem {
label: "Test Item".to_string(),
documentation: Some(lsp::Documentation::String(
"This is some very long documentation content that will be displayed in the aside panel for scrolling.\n".repeat(50)
)),
..Default::default()
},
])))
});
cx.set_state("variableˇ");
cx.simulate_keystroke(".");
cx.executor().run_until_parked();
// Verify that the completion menu is visible before attempting to scroll
// it's aside content.
let mut initial_offset: Pixels = px(0.0);
cx.update_editor(|editor, _, _| {
let binding = editor.context_menu.borrow();
let Some(CodeContextMenu::Completions(menu)) = binding.as_ref() else {
panic!("Should have completions menu open");
};
assert_eq!(completion_menu_entries(&menu), &["Test Item"]);
initial_offset = menu.scroll_handle_aside.offset().y;
});
// The `ctrl-e` shortcut should scroll the completion menu's aside content
// down, so the updated offset should be lower than the initial offset.
cx.simulate_keystroke("ctrl-e");
cx.update_editor(|editor, _, _| {
let binding = editor.context_menu.borrow();
let Some(CodeContextMenu::Completions(menu)) = binding.as_ref() else {
panic!("Should have completions menu open");
};
assert!(menu.scroll_handle_aside.offset().y < initial_offset);
});
// The `ctrl-y` shortcut should do the inverse scrolling as `ctrl-e`, so the
// offset should now be the same as the initial offset.
cx.simulate_keystroke("ctrl-y");
cx.update_editor(|editor, _, _| {
let binding = editor.context_menu.borrow();
let Some(CodeContextMenu::Completions(menu)) = binding.as_ref() else {
panic!("Should have completions menu open");
};
assert_eq!(menu.scroll_handle_aside.offset().y, initial_offset);
});
// The `ctrl-d` shortcut should scroll the completion menu's aside content
// down, so the updated offset should be lower than the initial offset.
cx.simulate_keystroke("ctrl-d");
cx.update_editor(|editor, _, _| {
let binding = editor.context_menu.borrow();
let Some(CodeContextMenu::Completions(menu)) = binding.as_ref() else {
panic!("Should have completions menu open");
};
assert!(menu.scroll_handle_aside.offset().y < initial_offset);
});
// The `ctrl-u` shortcut should do the inverse scrolling as `ctrl-u`, so the
// offset should now be the same as the initial offset.
cx.simulate_keystroke("ctrl-u");
cx.update_editor(|editor, _, _| {
let binding = editor.context_menu.borrow();
let Some(CodeContextMenu::Completions(menu)) = binding.as_ref() else {
panic!("Should have completions menu open");
};
assert_eq!(menu.scroll_handle_aside.offset().y, initial_offset);
});
}
#[track_caller]
fn extract_color_inlays(editor: &Editor, cx: &App) -> Vec<Rgba> {
editor

View file

@ -8,13 +8,15 @@ use collections::HashMap;
use command_palette::CommandPalette;
use editor::{
AnchorRangeExt, DisplayPoint, Editor, EditorMode, MultiBuffer, actions::DeleteLine,
display_map::DisplayRow, test::editor_test_context::EditorTestContext,
code_context_menus::CodeContextMenu, display_map::DisplayRow,
test::editor_test_context::EditorTestContext,
};
use futures::StreamExt;
use gpui::{KeyBinding, Modifiers, MouseButton, TestAppContext};
use gpui::{KeyBinding, Modifiers, MouseButton, TestAppContext, px};
use language::Point;
pub use neovim_backed_test_context::*;
use settings::SettingsStore;
use ui::Pixels;
use util::test::marked_text_ranges;
pub use vim_test_context::*;
@ -971,6 +973,87 @@ async fn test_comma_w(cx: &mut gpui::TestAppContext) {
.assert_eq("hellˇo hello\nhello hello");
}
#[gpui::test]
async fn test_completion_menu_scroll_aside(cx: &mut TestAppContext) {
let mut cx = VimTestContext::new_typescript(cx).await;
cx.lsp
.set_request_handler::<lsp::request::Completion, _, _>(move |_, _| async move {
Ok(Some(lsp::CompletionResponse::Array(vec![
lsp::CompletionItem {
label: "Test Item".to_string(),
documentation: Some(lsp::Documentation::String(
"This is some very long documentation content that will be displayed in the aside panel for scrolling.\n".repeat(50)
)),
..Default::default()
},
])))
});
cx.set_state("variableˇ", Mode::Insert);
cx.simulate_keystroke(".");
cx.executor().run_until_parked();
let mut initial_offset: Pixels = px(0.0);
cx.update_editor(|editor, _, _| {
let binding = editor.context_menu().borrow();
let Some(CodeContextMenu::Completions(menu)) = binding.as_ref() else {
panic!("Should have completions menu open");
};
initial_offset = menu.scroll_handle_aside.offset().y;
});
// The `ctrl-e` shortcut should scroll the completion menu's aside content
// down, so the updated offset should be lower than the initial offset.
cx.simulate_keystroke("ctrl-e");
cx.update_editor(|editor, _, _| {
let binding = editor.context_menu().borrow();
let Some(CodeContextMenu::Completions(menu)) = binding.as_ref() else {
panic!("Should have completions menu open");
};
assert!(menu.scroll_handle_aside.offset().y < initial_offset);
});
// The `ctrl-y` shortcut should do the inverse scrolling as `ctrl-e`, so the
// offset should now be the same as the initial offset.
cx.simulate_keystroke("ctrl-y");
cx.update_editor(|editor, _, _| {
let binding = editor.context_menu().borrow();
let Some(CodeContextMenu::Completions(menu)) = binding.as_ref() else {
panic!("Should have completions menu open");
};
assert_eq!(menu.scroll_handle_aside.offset().y, initial_offset);
});
// The `ctrl-d` shortcut should scroll the completion menu's aside content
// down, so the updated offset should be lower than the initial offset.
cx.simulate_keystroke("ctrl-d");
cx.update_editor(|editor, _, _| {
let binding = editor.context_menu().borrow();
let Some(CodeContextMenu::Completions(menu)) = binding.as_ref() else {
panic!("Should have completions menu open");
};
assert!(menu.scroll_handle_aside.offset().y < initial_offset);
});
// The `ctrl-u` shortcut should do the inverse scrolling as `ctrl-u`, so the
// offset should now be the same as the initial offset.
cx.simulate_keystroke("ctrl-u");
cx.update_editor(|editor, _, _| {
let binding = editor.context_menu().borrow();
let Some(CodeContextMenu::Completions(menu)) = binding.as_ref() else {
panic!("Should have completions menu open");
};
assert_eq!(menu.scroll_handle_aside.offset().y, initial_offset);
});
}
#[gpui::test]
async fn test_rename(cx: &mut gpui::TestAppContext) {
let mut cx = VimTestContext::new_typescript(cx).await;

View file

@ -49,6 +49,10 @@ impl VimTestContext {
Self::new_with_lsp(
EditorLspTestContext::new_typescript(
lsp::ServerCapabilities {
completion_provider: Some(lsp::CompletionOptions {
trigger_characters: Some(vec![".".to_string()]),
..Default::default()
}),
rename_provider: Some(lsp::OneOf::Right(lsp::RenameOptions {
prepare_provider: Some(true),
work_done_progress_options: Default::default(),