From adcaa211ecf4794171681efff490fa7687c31605 Mon Sep 17 00:00:00 2001 From: blufony <79605864+blufony@users.noreply.github.com> Date: Sat, 27 Apr 2024 00:35:57 +0200 Subject: [PATCH] Add keybindings to jump to first / last file in project panel (#11073) Release Notes: - vim: Support `g g`/`G` to go to top/bottom of the project panel. In vim type environments i usually expect to be able to jump to the top and bottom and i was confused as to why that wasn't possible in the project panel. So i added it. If anyone using different keymaps also thinks this might be useful i would be happy to add other defaults. I think for vim mode it is the most useful though, because you tend to not use your mouse in vim mode. This is my first contribution to any rust project, but it seemed like a good starting point. The function select_last() is inspired by select_first. I was also thinking about adding a bigger jump keybinding, that would jump for example 5 entries up / down, with vim default keybindings "{" / "}". FYI: I tested this on linux only and don't have access to any macos machines. - N/A --- assets/keymaps/vim.json | 4 +++- crates/project_panel/src/project_panel.rs | 29 +++++++++++++++++++---- 2 files changed, 28 insertions(+), 5 deletions(-) diff --git a/assets/keymaps/vim.json b/assets/keymaps/vim.json index 6fd497703a..24593404df 100644 --- a/assets/keymaps/vim.json +++ b/assets/keymaps/vim.json @@ -625,7 +625,9 @@ "t": "project_panel::OpenPermanent", "v": "project_panel::OpenPermanent", "p": "project_panel::Open", - "x": "project_panel::RevealInFinder" + "x": "project_panel::RevealInFinder", + "shift-g": "menu::SelectLast", + "g g": "menu::SelectFirst" } } ] diff --git a/crates/project_panel/src/project_panel.rs b/crates/project_panel/src/project_panel.rs index 286f058d1e..f55c9d5471 100644 --- a/crates/project_panel/src/project_panel.rs +++ b/crates/project_panel/src/project_panel.rs @@ -16,7 +16,7 @@ use gpui::{ ParentElement, Pixels, Point, PromptLevel, Render, Stateful, Styled, Subscription, Task, UniformListScrollHandle, View, ViewContext, VisualContext as _, WeakView, WindowContext, }; -use menu::{Confirm, SelectNext, SelectPrev}; +use menu::{Confirm, SelectFirst, SelectLast, SelectNext, SelectPrev}; use project::{Entry, EntryKind, Fs, Project, ProjectEntryId, ProjectPath, Worktree, WorktreeId}; use project_panel_settings::{ProjectPanelDockPosition, ProjectPanelSettings}; use serde::{Deserialize, Serialize}; @@ -644,7 +644,7 @@ impl ProjectPanel { self.autoscroll(cx); cx.notify(); } else { - self.select_first(cx); + self.select_first(&SelectFirst {}, cx); } } @@ -989,11 +989,11 @@ impl ProjectPanel { } } } else { - self.select_first(cx); + self.select_first(&SelectFirst {}, cx); } } - fn select_first(&mut self, cx: &mut ViewContext) { + fn select_first(&mut self, _: &SelectFirst, cx: &mut ViewContext) { let worktree = self .visible_entries .first() @@ -1012,6 +1012,25 @@ impl ProjectPanel { } } + fn select_last(&mut self, _: &SelectLast, cx: &mut ViewContext) { + let worktree = self + .visible_entries + .last() + .and_then(|(worktree_id, _)| self.project.read(cx).worktree_for_id(*worktree_id, cx)); + if let Some(worktree) = worktree { + let worktree = worktree.read(cx); + let worktree_id = worktree.id(); + if let Some(last_entry) = worktree.entries(true).last() { + self.selection = Some(Selection { + worktree_id, + entry_id: last_entry.id, + }); + self.autoscroll(cx); + cx.notify(); + } + } + } + fn autoscroll(&mut self, cx: &mut ViewContext) { if let Some((_, _, index)) = self.selection.and_then(|s| self.index_for_selection(s)) { self.scroll_handle.scroll_to_item(index); @@ -1751,6 +1770,8 @@ impl Render for ProjectPanel { .key_context(self.dispatch_context(cx)) .on_action(cx.listener(Self::select_next)) .on_action(cx.listener(Self::select_prev)) + .on_action(cx.listener(Self::select_first)) + .on_action(cx.listener(Self::select_last)) .on_action(cx.listener(Self::expand_selected_entry)) .on_action(cx.listener(Self::collapse_selected_entry)) .on_action(cx.listener(Self::collapse_all_entries))