project_panel vim counts and shortcuts
This commit is contained in:
parent
c731bb6d91
commit
d08b72b872
6 changed files with 169 additions and 17 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -17937,6 +17937,7 @@ dependencies = [
|
|||
"language",
|
||||
"log",
|
||||
"lsp",
|
||||
"menu",
|
||||
"multi_buffer",
|
||||
"nvim-rs",
|
||||
"parking_lot",
|
||||
|
|
|
@ -733,6 +733,21 @@
|
|||
"escape": "buffer_search::Dismiss"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "(GitPanel || ProjectPanel || CollabPanel || OutlinePanel || ChatPanel || EmptyPane || SharedScreen || MarkdownPreview || KeyContextView || DebugPanel) && not_editing",
|
||||
"bindings": {
|
||||
"0": ["vim::Number", 0],
|
||||
"1": ["vim::Number", 1],
|
||||
"2": ["vim::Number", 2],
|
||||
"3": ["vim::Number", 3],
|
||||
"4": ["vim::Number", 4],
|
||||
"5": ["vim::Number", 5],
|
||||
"6": ["vim::Number", 6],
|
||||
"7": ["vim::Number", 7],
|
||||
"8": ["vim::Number", 8],
|
||||
"9": ["vim::Number", 9]
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "VimControl || !Editor && !Terminal",
|
||||
"bindings": {
|
||||
|
@ -809,8 +824,8 @@
|
|||
"enter": "project_panel::OpenPermanent",
|
||||
"escape": "project_panel::ToggleFocus",
|
||||
"h": "project_panel::CollapseSelectedEntry",
|
||||
"j": "menu::SelectNext",
|
||||
"k": "menu::SelectPrevious",
|
||||
"j": "vim::MenuSelectNext",
|
||||
"k": "vim::MenuSelectPrevious",
|
||||
"l": "project_panel::ExpandSelectedEntry",
|
||||
"o": "project_panel::OpenPermanent",
|
||||
"shift-d": "project_panel::Delete",
|
||||
|
@ -829,7 +844,12 @@
|
|||
"{": "project_panel::SelectPrevDirectory",
|
||||
"shift-g": "menu::SelectLast",
|
||||
"g g": "menu::SelectFirst",
|
||||
"-": "project_panel::SelectParent"
|
||||
"-": "project_panel::SelectParent",
|
||||
"ctrl-u": "project_panel::ScrollUp",
|
||||
"ctrl-d": "project_panel::ScrollDown",
|
||||
"z t": "project_panel::ScrollCursorTop",
|
||||
"z z": "project_panel::ScrollCursorCenter",
|
||||
"z b": "project_panel::ScrollCursorBottom"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -88,6 +88,10 @@ pub enum ScrollStrategy {
|
|||
/// May not be possible if there's not enough list items above the item scrolled to:
|
||||
/// in this case, the element will be placed at the closest possible position.
|
||||
Center,
|
||||
/// Attempt to place the element at the bottom of the list's viewport.
|
||||
/// May not be possible if there's not enough list items above the item scrolled to:
|
||||
/// in this case, the element will be placed at the closest possible position.
|
||||
Bottom,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
|
@ -99,6 +103,7 @@ pub struct DeferredScrollToItem {
|
|||
pub strategy: ScrollStrategy,
|
||||
/// The offset in number of items
|
||||
pub offset: usize,
|
||||
pub scroll_strict: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
|
@ -133,12 +138,23 @@ impl UniformListScrollHandle {
|
|||
})))
|
||||
}
|
||||
|
||||
/// Scroll the list to the given item index.
|
||||
/// Scroll the list so that the given item index is onscreen.
|
||||
pub fn scroll_to_item(&self, ix: usize, strategy: ScrollStrategy) {
|
||||
self.0.borrow_mut().deferred_scroll_to_item = Some(DeferredScrollToItem {
|
||||
item_index: ix,
|
||||
strategy,
|
||||
offset: 0,
|
||||
scroll_strict: false,
|
||||
});
|
||||
}
|
||||
|
||||
/// Scroll the list so that the given item index is at scroll strategy position.
|
||||
pub fn scroll_to_item_strict(&self, ix: usize, strategy: ScrollStrategy) {
|
||||
self.0.borrow_mut().deferred_scroll_to_item = Some(DeferredScrollToItem {
|
||||
item_index: ix,
|
||||
strategy,
|
||||
offset: 0,
|
||||
scroll_strict: true,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -152,6 +168,7 @@ impl UniformListScrollHandle {
|
|||
item_index: ix,
|
||||
strategy,
|
||||
offset,
|
||||
scroll_strict: false,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -368,24 +385,35 @@ impl Element for UniformList {
|
|||
updated_scroll_offset.y = -(item_bottom - list_height) - padding.bottom;
|
||||
}
|
||||
|
||||
match deferred_scroll.strategy {
|
||||
ScrollStrategy::Top => {}
|
||||
ScrollStrategy::Center => {
|
||||
if scrolled_to_top {
|
||||
if deferred_scroll.scroll_strict
|
||||
|| (scrolled_to_top
|
||||
&& (item_top < scroll_top + offset_pixels
|
||||
|| item_bottom > scroll_top + list_height))
|
||||
{
|
||||
match deferred_scroll.strategy {
|
||||
ScrollStrategy::Top => {
|
||||
updated_scroll_offset.y = -item_top
|
||||
.max(Pixels::ZERO)
|
||||
.min(content_height - list_height)
|
||||
.max(Pixels::ZERO);
|
||||
}
|
||||
ScrollStrategy::Center => {
|
||||
let item_center = item_top + item_height / 2.0;
|
||||
|
||||
let viewport_height = list_height - offset_pixels;
|
||||
let viewport_center = offset_pixels + viewport_height / 2.0;
|
||||
let target_scroll_top = item_center - viewport_center;
|
||||
|
||||
if item_top < scroll_top + offset_pixels
|
||||
|| item_bottom > scroll_top + list_height
|
||||
{
|
||||
updated_scroll_offset.y = -target_scroll_top
|
||||
.max(Pixels::ZERO)
|
||||
.min(content_height - list_height)
|
||||
.max(Pixels::ZERO);
|
||||
}
|
||||
updated_scroll_offset.y = -target_scroll_top
|
||||
.max(Pixels::ZERO)
|
||||
.min(content_height - list_height)
|
||||
.max(Pixels::ZERO);
|
||||
}
|
||||
ScrollStrategy::Bottom => {
|
||||
updated_scroll_offset.y = -(item_bottom - list_height)
|
||||
.max(Pixels::ZERO)
|
||||
.min(content_height - list_height)
|
||||
.max(Pixels::ZERO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,6 +87,7 @@ pub struct ProjectPanel {
|
|||
// An update loop that keeps incrementing/decrementing scroll offset while there is a dragged entry that's
|
||||
// hovered over the start/end of a list.
|
||||
hover_scroll_task: Option<Task<()>>,
|
||||
rendered_entries_len: usize,
|
||||
visible_entries: Vec<VisibleEntriesForWorktree>,
|
||||
/// Maps from leaf project entry ID to the currently selected ancestor.
|
||||
/// Relevant only for auto-fold dirs, where a single project panel entry may actually consist of several
|
||||
|
@ -277,6 +278,11 @@ actions!(
|
|||
UnfoldDirectory,
|
||||
/// Folds the selected directory.
|
||||
FoldDirectory,
|
||||
ScrollUp,
|
||||
ScrollDown,
|
||||
ScrollCursorCenter,
|
||||
ScrollCursorTop,
|
||||
ScrollCursorBottom,
|
||||
/// Selects the parent directory.
|
||||
SelectParent,
|
||||
/// Selects the next entry with git changes.
|
||||
|
@ -603,6 +609,7 @@ impl ProjectPanel {
|
|||
hover_scroll_task: None,
|
||||
fs: workspace.app_state().fs.clone(),
|
||||
focus_handle,
|
||||
rendered_entries_len: 0,
|
||||
visible_entries: Default::default(),
|
||||
ancestors: Default::default(),
|
||||
folded_directory_drag_target: None,
|
||||
|
@ -1989,6 +1996,52 @@ impl ProjectPanel {
|
|||
}
|
||||
}
|
||||
|
||||
fn scroll_up(&mut self, _: &ScrollUp, window: &mut Window, cx: &mut Context<Self>) {
|
||||
for _ in 0..self.rendered_entries_len / 2 {
|
||||
window.dispatch_action(SelectPrevious.boxed_clone(), cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn scroll_down(&mut self, _: &ScrollDown, window: &mut Window, cx: &mut Context<Self>) {
|
||||
for _ in 0..self.rendered_entries_len / 2 {
|
||||
window.dispatch_action(SelectNext.boxed_clone(), cx);
|
||||
}
|
||||
}
|
||||
|
||||
fn scroll_cursor_center(
|
||||
&mut self,
|
||||
_: &ScrollCursorCenter,
|
||||
_: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Some((_, _, index)) = self.selection.and_then(|s| self.index_for_selection(s)) {
|
||||
self.scroll_handle
|
||||
.scroll_to_item_strict(index, ScrollStrategy::Center);
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn scroll_cursor_top(&mut self, _: &ScrollCursorTop, _: &mut Window, cx: &mut Context<Self>) {
|
||||
if let Some((_, _, index)) = self.selection.and_then(|s| self.index_for_selection(s)) {
|
||||
self.scroll_handle
|
||||
.scroll_to_item_strict(index, ScrollStrategy::Top);
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn scroll_cursor_bottom(
|
||||
&mut self,
|
||||
_: &ScrollCursorBottom,
|
||||
_: &mut Window,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
if let Some((_, _, index)) = self.selection.and_then(|s| self.index_for_selection(s)) {
|
||||
self.scroll_handle
|
||||
.scroll_to_item_strict(index, ScrollStrategy::Bottom);
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
fn select_next(&mut self, _: &SelectNext, window: &mut Window, cx: &mut Context<Self>) {
|
||||
if let Some(edit_state) = &self.edit_state
|
||||
&& edit_state.processing_filename.is_none()
|
||||
|
@ -5233,6 +5286,11 @@ impl Render for ProjectPanel {
|
|||
this.marked_entries.clear();
|
||||
}))
|
||||
.key_context(self.dispatch_context(window, cx))
|
||||
.on_action(cx.listener(Self::scroll_up))
|
||||
.on_action(cx.listener(Self::scroll_down))
|
||||
.on_action(cx.listener(Self::scroll_cursor_center))
|
||||
.on_action(cx.listener(Self::scroll_cursor_top))
|
||||
.on_action(cx.listener(Self::scroll_cursor_bottom))
|
||||
.on_action(cx.listener(Self::select_next))
|
||||
.on_action(cx.listener(Self::select_previous))
|
||||
.on_action(cx.listener(Self::select_first))
|
||||
|
@ -5313,7 +5371,8 @@ impl Render for ProjectPanel {
|
|||
.child(
|
||||
uniform_list("entries", item_count, {
|
||||
cx.processor(|this, range: Range<usize>, window, cx| {
|
||||
let mut items = Vec::with_capacity(range.end - range.start);
|
||||
this.rendered_entries_len = range.end - range.start;
|
||||
let mut items = Vec::with_capacity(this.rendered_entries_len);
|
||||
this.for_each_visible_entry(
|
||||
range,
|
||||
window,
|
||||
|
|
|
@ -44,6 +44,7 @@ settings.workspace = true
|
|||
task.workspace = true
|
||||
text.workspace = true
|
||||
theme.workspace = true
|
||||
menu.workspace = true
|
||||
tokio = { version = "1.15", features = ["full"], optional = true }
|
||||
ui.workspace = true
|
||||
util.workspace = true
|
||||
|
|
|
@ -222,6 +222,8 @@ actions!(
|
|||
PushReplaceWithRegister,
|
||||
/// Toggles comments.
|
||||
PushToggleComments,
|
||||
MenuSelectNext,
|
||||
MenuSelectPrevious
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -251,6 +253,47 @@ pub fn init(cx: &mut App) {
|
|||
})
|
||||
});
|
||||
|
||||
workspace.register_action(|_, _: &MenuSelectNext, window, cx| {
|
||||
let count = Vim::take_count(cx).unwrap_or(1);
|
||||
|
||||
for _ in 0..count {
|
||||
window.dispatch_action(menu::SelectNext.boxed_clone(), cx);
|
||||
}
|
||||
});
|
||||
|
||||
workspace.register_action(|_, _: &MenuSelectPrevious, window, cx| {
|
||||
let count = Vim::take_count(cx).unwrap_or(1);
|
||||
|
||||
for _ in 0..count {
|
||||
window.dispatch_action(menu::SelectPrevious.boxed_clone(), cx);
|
||||
}
|
||||
});
|
||||
|
||||
workspace.register_action(|workspace, n: &Number, window, cx| {
|
||||
let vim = workspace
|
||||
.focused_pane(window, cx)
|
||||
.read(cx)
|
||||
.active_item()
|
||||
.and_then(|item| item.act_as::<Editor>(cx))
|
||||
.and_then(|editor| editor.read(cx).addon::<VimAddon>().cloned());
|
||||
if let Some(vim) = vim {
|
||||
let digit = n.0;
|
||||
vim.entity.update(cx, |_, cx| {
|
||||
cx.defer_in(window, move |vim, window, cx| {
|
||||
vim.push_count_digit(digit, window, cx)
|
||||
})
|
||||
});
|
||||
} else {
|
||||
let count = Vim::globals(cx).pre_count.unwrap_or(0);
|
||||
Vim::globals(cx).pre_count = Some(
|
||||
count
|
||||
.checked_mul(10)
|
||||
.and_then(|c| c.checked_add(n.0))
|
||||
.unwrap_or(count),
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
workspace.register_action(|_, _: &OpenDefaultKeymap, _, cx| {
|
||||
cx.emit(workspace::Event::OpenBundledFile {
|
||||
text: settings::vim_keymap(),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue