Merge pull request #2188 from zed-industries/dont-open-project-items-in-dock

Dont open project items in dock
This commit is contained in:
Kay Simmons 2023-02-18 13:53:29 -08:00 committed by GitHub
commit efafd1d8d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 199 additions and 128 deletions

View File

@ -450,15 +450,16 @@
}
},
{
"context": "Dock",
"context": "Pane",
"bindings": {
"shift-escape": "dock::HideDock"
"cmd-escape": "dock::AddTabToDock"
}
},
{
"context": "Pane",
"context": "Dock",
"bindings": {
"cmd-escape": "dock::MoveActiveItemToDock"
"shift-escape": "dock::HideDock",
"cmd-escape": "dock::RemoveTabFromDock"
}
},
{

View File

@ -5,7 +5,7 @@ mod keystroke;
use std::{any::TypeId, fmt::Debug};
use collections::HashMap;
use collections::{BTreeMap, HashMap};
use smallvec::SmallVec;
use crate::Action;
@ -60,13 +60,28 @@ impl KeymapMatcher {
!self.pending_keystrokes.is_empty()
}
/// Pushes a keystroke onto the matcher.
/// The result of the new keystroke is returned:
/// MatchResult::None =>
/// No match is valid for this key given any pending keystrokes.
/// MatchResult::Pending =>
/// There exist bindings which are still waiting for more keys.
/// MatchResult::Complete(matches) =>
/// 1 or more bindings have recieved the necessary key presses.
/// The order of the matched actions is by order in the keymap file first and
/// position of the matching view second.
pub fn push_keystroke(
&mut self,
keystroke: Keystroke,
mut dispatch_path: Vec<(usize, KeymapContext)>,
) -> MatchResult {
let mut any_pending = false;
let mut matched_bindings: Vec<(usize, Box<dyn Action>)> = Vec::new();
// Collect matched bindings into an ordered list using the position in the matching binding first,
// and then the order the binding matched in the view tree second.
// The key is the reverse position of the binding in the bindings list so that later bindings
// match before earlier ones in the user's config
let mut matched_bindings: BTreeMap<usize, Vec<(usize, Box<dyn Action>)>> =
Default::default();
let first_keystroke = self.pending_keystrokes.is_empty();
self.pending_keystrokes.push(keystroke.clone());
@ -75,29 +90,33 @@ impl KeymapMatcher {
self.contexts
.extend(dispatch_path.iter_mut().map(|e| std::mem::take(&mut e.1)));
for (i, (view_id, _)) in dispatch_path.into_iter().enumerate() {
// Find the bindings which map the pending keystrokes and current context
for (i, (view_id, _)) in dispatch_path.iter().enumerate() {
// Don't require pending view entry if there are no pending keystrokes
if !first_keystroke && !self.pending_views.contains_key(&view_id) {
if !first_keystroke && !self.pending_views.contains_key(view_id) {
continue;
}
// If there is a previous view context, invalidate that view if it
// has changed
if let Some(previous_view_context) = self.pending_views.remove(&view_id) {
if let Some(previous_view_context) = self.pending_views.remove(view_id) {
if previous_view_context != self.contexts[i] {
continue;
}
}
// Find the bindings which map the pending keystrokes and current context
for binding in self.keymap.bindings().iter().rev() {
for (order, binding) in self.keymap.bindings().iter().rev().enumerate() {
match binding.match_keys_and_context(&self.pending_keystrokes, &self.contexts[i..])
{
BindingMatchResult::Complete(action) => {
matched_bindings.push((view_id, action))
matched_bindings
.entry(order)
.or_default()
.push((*view_id, action));
}
BindingMatchResult::Partial => {
self.pending_views.insert(view_id, self.contexts[i].clone());
self.pending_views
.insert(*view_id, self.contexts[i].clone());
any_pending = true;
}
_ => {}
@ -110,7 +129,9 @@ impl KeymapMatcher {
}
if !matched_bindings.is_empty() {
MatchResult::Matches(matched_bindings)
// Collect the sorted matched bindings into the final vec for ease of use
// Matched bindings are in order by precedence
MatchResult::Matches(matched_bindings.into_values().flatten().collect())
} else if any_pending {
MatchResult::Pending
} else {

View File

@ -1,19 +1,20 @@
mod toggle_dock_button;
use serde::Deserialize;
use collections::HashMap;
use gpui::{
actions,
elements::{ChildView, Container, Empty, MouseEventHandler, ParentElement, Side, Stack, Svg},
elements::{ChildView, Container, Empty, MouseEventHandler, ParentElement, Side, Stack},
geometry::vector::Vector2F,
impl_internal_actions, Border, CursorStyle, Element, ElementBox, Entity, MouseButton,
MutableAppContext, RenderContext, SizeConstraint, View, ViewContext, ViewHandle,
WeakViewHandle,
impl_internal_actions, Border, CursorStyle, Element, ElementBox, MouseButton,
MutableAppContext, RenderContext, SizeConstraint, ViewContext, ViewHandle,
};
use serde::Deserialize;
use settings::{DockAnchor, Settings};
use theme::Theme;
use crate::{
handle_dropped_item, sidebar::SidebarSide, ItemHandle, Pane, StatusItemView, Workspace,
};
use crate::{sidebar::SidebarSide, ItemHandle, Pane, Workspace};
pub use toggle_dock_button::ToggleDockButton;
#[derive(PartialEq, Clone, Deserialize)]
pub struct MoveDock(pub DockAnchor);
@ -29,7 +30,8 @@ actions!(
AnchorDockRight,
AnchorDockBottom,
ExpandDock,
MoveActiveItemToDock,
AddTabToDock,
RemoveTabFromDock,
]
);
impl_internal_actions!(dock, [MoveDock, AddDefaultItemToDock]);
@ -54,7 +56,8 @@ pub fn init(cx: &mut MutableAppContext) {
},
);
cx.add_action(
|workspace: &mut Workspace, _: &MoveActiveItemToDock, cx: &mut ViewContext<Workspace>| {
|workspace: &mut Workspace, _: &AddTabToDock, cx: &mut ViewContext<Workspace>| {
eprintln!("Add tab to dock");
if let Some(active_item) = workspace.active_item(cx) {
let item_id = active_item.id();
@ -66,6 +69,42 @@ pub fn init(cx: &mut MutableAppContext) {
let destination_index = to.read(cx).items_len() + 1;
Pane::move_item(
workspace,
from.clone(),
to.clone(),
item_id,
destination_index,
cx,
);
}
},
);
cx.add_action(
|workspace: &mut Workspace, _: &RemoveTabFromDock, cx: &mut ViewContext<Workspace>| {
eprintln!("Removing tab from dock");
if let Some(active_item) = workspace.active_item(cx) {
let item_id = active_item.id();
let from = workspace.dock_pane();
let to = workspace
.last_active_center_pane
.as_ref()
.and_then(|pane| pane.upgrade(cx))
.unwrap_or_else(|| {
workspace
.panes
.first()
.expect("There must be a pane")
.clone()
});
if from.id() == to.id() {
return;
}
let destination_index = to.read(cx).items_len() + 1;
Pane::move_item(
workspace,
from.clone(),
@ -376,108 +415,6 @@ impl Dock {
}
}
pub struct ToggleDockButton {
workspace: WeakViewHandle<Workspace>,
}
impl ToggleDockButton {
pub fn new(workspace: ViewHandle<Workspace>, cx: &mut ViewContext<Self>) -> Self {
// When dock moves, redraw so that the icon and toggle status matches.
cx.subscribe(&workspace, |_, _, _, cx| cx.notify()).detach();
Self {
workspace: workspace.downgrade(),
}
}
}
impl Entity for ToggleDockButton {
type Event = ();
}
impl View for ToggleDockButton {
fn ui_name() -> &'static str {
"Dock Toggle"
}
fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox {
let workspace = self.workspace.upgrade(cx);
if workspace.is_none() {
return Empty::new().boxed();
}
let workspace = workspace.unwrap();
let dock_position = workspace.read(cx).dock.position;
let theme = cx.global::<Settings>().theme.clone();
let button = MouseEventHandler::<Self>::new(0, cx, {
let theme = theme.clone();
move |state, _| {
let style = theme
.workspace
.status_bar
.sidebar_buttons
.item
.style_for(state, dock_position.is_visible());
Svg::new(icon_for_dock_anchor(dock_position.anchor()))
.with_color(style.icon_color)
.constrained()
.with_width(style.icon_size)
.with_height(style.icon_size)
.contained()
.with_style(style.container)
.boxed()
}
})
.with_cursor_style(CursorStyle::PointingHand)
.on_up(MouseButton::Left, move |event, cx| {
let dock_pane = workspace.read(cx.app).dock_pane();
let drop_index = dock_pane.read(cx.app).items_len() + 1;
handle_dropped_item(event, &dock_pane.downgrade(), drop_index, false, None, cx);
});
if dock_position.is_visible() {
button
.on_click(MouseButton::Left, |_, cx| {
cx.dispatch_action(HideDock);
})
.with_tooltip::<Self, _>(
0,
"Hide Dock".into(),
Some(Box::new(HideDock)),
theme.tooltip.clone(),
cx,
)
} else {
button
.on_click(MouseButton::Left, |_, cx| {
cx.dispatch_action(FocusDock);
})
.with_tooltip::<Self, _>(
0,
"Focus Dock".into(),
Some(Box::new(FocusDock)),
theme.tooltip.clone(),
cx,
)
}
.boxed()
}
}
impl StatusItemView for ToggleDockButton {
fn set_active_pane_item(
&mut self,
_active_pane_item: Option<&dyn crate::ItemHandle>,
_cx: &mut ViewContext<Self>,
) {
//Not applicable
}
}
#[cfg(test)]
mod tests {
use std::{
@ -485,7 +422,7 @@ mod tests {
path::PathBuf,
};
use gpui::{AppContext, TestAppContext, UpdateView, ViewContext};
use gpui::{AppContext, TestAppContext, UpdateView, View, ViewContext};
use project::{FakeFs, Project};
use settings::Settings;

View File

@ -0,0 +1,112 @@
use gpui::{
elements::{Empty, MouseEventHandler, Svg},
CursorStyle, Element, ElementBox, Entity, MouseButton, View, ViewContext, ViewHandle,
WeakViewHandle,
};
use settings::Settings;
use crate::{handle_dropped_item, StatusItemView, Workspace};
use super::{icon_for_dock_anchor, FocusDock, HideDock};
pub struct ToggleDockButton {
workspace: WeakViewHandle<Workspace>,
}
impl ToggleDockButton {
pub fn new(workspace: ViewHandle<Workspace>, cx: &mut ViewContext<Self>) -> Self {
// When dock moves, redraw so that the icon and toggle status matches.
cx.subscribe(&workspace, |_, _, _, cx| cx.notify()).detach();
Self {
workspace: workspace.downgrade(),
}
}
}
impl Entity for ToggleDockButton {
type Event = ();
}
impl View for ToggleDockButton {
fn ui_name() -> &'static str {
"Dock Toggle"
}
fn render(&mut self, cx: &mut gpui::RenderContext<'_, Self>) -> ElementBox {
let workspace = self.workspace.upgrade(cx);
if workspace.is_none() {
return Empty::new().boxed();
}
let workspace = workspace.unwrap();
let dock_position = workspace.read(cx).dock.position;
let theme = cx.global::<Settings>().theme.clone();
let button = MouseEventHandler::<Self>::new(0, cx, {
let theme = theme.clone();
move |state, _| {
let style = theme
.workspace
.status_bar
.sidebar_buttons
.item
.style_for(state, dock_position.is_visible());
Svg::new(icon_for_dock_anchor(dock_position.anchor()))
.with_color(style.icon_color)
.constrained()
.with_width(style.icon_size)
.with_height(style.icon_size)
.contained()
.with_style(style.container)
.boxed()
}
})
.with_cursor_style(CursorStyle::PointingHand)
.on_up(MouseButton::Left, move |event, cx| {
let dock_pane = workspace.read(cx.app).dock_pane();
let drop_index = dock_pane.read(cx.app).items_len() + 1;
handle_dropped_item(event, &dock_pane.downgrade(), drop_index, false, None, cx);
});
if dock_position.is_visible() {
button
.on_click(MouseButton::Left, |_, cx| {
cx.dispatch_action(HideDock);
})
.with_tooltip::<Self, _>(
0,
"Hide Dock".into(),
Some(Box::new(HideDock)),
theme.tooltip.clone(),
cx,
)
} else {
button
.on_click(MouseButton::Left, |_, cx| {
cx.dispatch_action(FocusDock);
})
.with_tooltip::<Self, _>(
0,
"Focus Dock".into(),
Some(Box::new(FocusDock)),
theme.tooltip.clone(),
cx,
)
}
.boxed()
}
}
impl StatusItemView for ToggleDockButton {
fn set_active_pane_item(
&mut self,
_active_pane_item: Option<&dyn crate::ItemHandle>,
_cx: &mut ViewContext<Self>,
) {
//Not applicable
}
}

View File

@ -1432,7 +1432,7 @@ impl View for Pane {
enum TabBarEventHandler {}
stack.add_child(
MouseEventHandler::<TabBarEventHandler>::new(0, cx, |_, _| {
Flex::row()
Empty::new()
.contained()
.with_style(theme.workspace.tab_bar.container)
.boxed()