Merge 398f9665c9
into 0e575b2809
This commit is contained in:
commit
1a6fa47c5d
7 changed files with 155 additions and 15 deletions
|
@ -324,7 +324,7 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"context": "vim_mode == insert",
|
||||
"context": "vim_mode == insert && !menu",
|
||||
"bindings": {
|
||||
"ctrl-c": "vim::NormalBefore",
|
||||
"ctrl-[": "vim::NormalBefore",
|
||||
|
@ -354,6 +354,15 @@
|
|||
"ctrl-s": "editor::ShowSignatureHelp"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "showing_completions",
|
||||
"bindings": {
|
||||
"ctrl-d": "vim::ScrollDown",
|
||||
"ctrl-u": "vim::ScrollUp",
|
||||
"ctrl-e": "vim::LineDown",
|
||||
"ctrl-y": "vim::LineUp"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "(vim_mode == normal || vim_mode == helix_normal) && !menu",
|
||||
"bindings": {
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
use crate::scroll::ScrollAmount;
|
||||
use fuzzy::{StringMatch, StringMatchCandidate};
|
||||
use gpui::{
|
||||
AnyElement, Entity, Focusable, FontWeight, ListSizingBehavior, ScrollStrategy, SharedString,
|
||||
Size, StrikethroughStyle, StyledText, Task, UniformListScrollHandle, div, px, uniform_list,
|
||||
AnyElement, Entity, Focusable, FontWeight, ListSizingBehavior, ScrollHandle, ScrollStrategy,
|
||||
SharedString, Size, StrikethroughStyle, StyledText, Task, UniformListScrollHandle, div, px,
|
||||
uniform_list,
|
||||
};
|
||||
use itertools::Itertools;
|
||||
use language::CodeLabel;
|
||||
|
@ -184,6 +186,20 @@ impl CodeContextMenu {
|
|||
CodeContextMenu::CodeActions(_) => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scroll_aside(
|
||||
&mut self,
|
||||
scroll_amount: ScrollAmount,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Editor>,
|
||||
) {
|
||||
match self {
|
||||
CodeContextMenu::Completions(completions_menu) => {
|
||||
completions_menu.scroll_aside(scroll_amount, window, cx)
|
||||
}
|
||||
CodeContextMenu::CodeActions(_) => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub enum ContextMenuOrigin {
|
||||
|
@ -207,6 +223,9 @@ pub struct CompletionsMenu {
|
|||
filter_task: Task<()>,
|
||||
cancel_filter: Arc<AtomicBool>,
|
||||
scroll_handle: UniformListScrollHandle,
|
||||
// The `ScrollHandle` used on the Markdown documentation rendered on the
|
||||
// side of the completions menu.
|
||||
pub scroll_handle_aside: ScrollHandle,
|
||||
resolve_completions: bool,
|
||||
show_completion_documentation: bool,
|
||||
last_rendered_range: Rc<RefCell<Option<Range<usize>>>>,
|
||||
|
@ -279,6 +298,7 @@ impl CompletionsMenu {
|
|||
filter_task: Task::ready(()),
|
||||
cancel_filter: Arc::new(AtomicBool::new(false)),
|
||||
scroll_handle: UniformListScrollHandle::new(),
|
||||
scroll_handle_aside: ScrollHandle::new(),
|
||||
resolve_completions: true,
|
||||
last_rendered_range: RefCell::new(None).into(),
|
||||
markdown_cache: RefCell::new(VecDeque::new()).into(),
|
||||
|
@ -348,6 +368,7 @@ impl CompletionsMenu {
|
|||
filter_task: Task::ready(()),
|
||||
cancel_filter: Arc::new(AtomicBool::new(false)),
|
||||
scroll_handle: UniformListScrollHandle::new(),
|
||||
scroll_handle_aside: ScrollHandle::new(),
|
||||
resolve_completions: false,
|
||||
show_completion_documentation: false,
|
||||
last_rendered_range: RefCell::new(None).into(),
|
||||
|
@ -911,6 +932,7 @@ impl CompletionsMenu {
|
|||
.max_w(max_size.width)
|
||||
.max_h(max_size.height)
|
||||
.overflow_y_scroll()
|
||||
.track_scroll(&self.scroll_handle_aside)
|
||||
.occlude(),
|
||||
)
|
||||
.into_any_element(),
|
||||
|
@ -1175,6 +1197,23 @@ impl CompletionsMenu {
|
|||
}
|
||||
});
|
||||
}
|
||||
|
||||
pub fn scroll_aside(
|
||||
&mut self,
|
||||
amount: ScrollAmount,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Editor>,
|
||||
) {
|
||||
let mut offset = self.scroll_handle_aside.offset();
|
||||
|
||||
offset.y -= amount.pixels(
|
||||
window.line_height(),
|
||||
self.scroll_handle_aside.bounds().size.height - px(16.),
|
||||
) / 2.0;
|
||||
|
||||
cx.notify();
|
||||
self.scroll_handle_aside.set_offset(offset);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
|
|
@ -188,22 +188,27 @@ impl Editor {
|
|||
|
||||
pub fn scroll_hover(
|
||||
&mut self,
|
||||
amount: &ScrollAmount,
|
||||
amount: ScrollAmount,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) -> bool {
|
||||
let selection = self.selections.newest_anchor().head();
|
||||
let snapshot = self.snapshot(window, cx);
|
||||
|
||||
let Some(popover) = self.hover_state.info_popovers.iter().find(|popover| {
|
||||
if let Some(popover) = self.hover_state.info_popovers.iter().find(|popover| {
|
||||
popover
|
||||
.symbol_range
|
||||
.point_within_range(&TriggerPoint::Text(selection), &snapshot)
|
||||
}) else {
|
||||
return false;
|
||||
}) {
|
||||
popover.scroll(&amount, window, cx);
|
||||
return true;
|
||||
};
|
||||
popover.scroll(amount, window, cx);
|
||||
true
|
||||
if let Some(context_menu) = self.context_menu.borrow_mut().as_mut() {
|
||||
context_menu.scroll_aside(amount, window, cx);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
fn cmd_click_reveal_task(
|
||||
|
|
|
@ -15,7 +15,7 @@ impl ScrollDirection {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Deserialize)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Deserialize)]
|
||||
pub enum ScrollAmount {
|
||||
// Scroll N lines (positive is towards the end of the document)
|
||||
Line(f32),
|
||||
|
|
|
@ -98,7 +98,7 @@ impl Vim {
|
|||
Vim::take_forced_motion(cx);
|
||||
self.exit_temporary_normal(window, cx);
|
||||
self.update_editor(cx, |_, editor, cx| {
|
||||
scroll_editor(editor, move_cursor, &amount, window, cx)
|
||||
scroll_editor(editor, move_cursor, amount, window, cx)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ impl Vim {
|
|||
fn scroll_editor(
|
||||
editor: &mut Editor,
|
||||
preserve_cursor_position: bool,
|
||||
amount: &ScrollAmount,
|
||||
amount: ScrollAmount,
|
||||
window: &mut Window,
|
||||
cx: &mut Context<Editor>,
|
||||
) {
|
||||
|
@ -126,7 +126,7 @@ fn scroll_editor(
|
|||
ScrollAmount::Line(amount.lines(visible_line_count) - 1.0)
|
||||
}
|
||||
}
|
||||
_ => amount.clone(),
|
||||
_ => amount,
|
||||
};
|
||||
|
||||
editor.scroll_screen(&amount, window, cx);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue