Merge branch 'main' into vim-search
This commit is contained in:
commit
98b8008bcc
48 changed files with 2447 additions and 968 deletions
|
@ -10,6 +10,9 @@ use gpui::{
|
|||
ViewContext, ViewHandle, WeakViewHandle, WindowContext,
|
||||
};
|
||||
use project::{Project, ProjectEntryId, ProjectPath};
|
||||
use schemars::JsonSchema;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use settings::Setting;
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
|
@ -27,6 +30,49 @@ use std::{
|
|||
};
|
||||
use theme::Theme;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct ItemSettings {
|
||||
pub git_status: bool,
|
||||
pub close_position: ClosePosition,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum ClosePosition {
|
||||
Left,
|
||||
#[default]
|
||||
Right,
|
||||
}
|
||||
|
||||
impl ClosePosition {
|
||||
pub fn right(&self) -> bool {
|
||||
match self {
|
||||
ClosePosition::Left => false,
|
||||
ClosePosition::Right => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||
pub struct ItemSettingsContent {
|
||||
git_status: Option<bool>,
|
||||
close_position: Option<ClosePosition>,
|
||||
}
|
||||
|
||||
impl Setting for ItemSettings {
|
||||
const KEY: Option<&'static str> = Some("tabs");
|
||||
|
||||
type FileContent = ItemSettingsContent;
|
||||
|
||||
fn load(
|
||||
default_value: &Self::FileContent,
|
||||
user_values: &[&Self::FileContent],
|
||||
_: &gpui::AppContext,
|
||||
) -> anyhow::Result<Self> {
|
||||
Self::load_via_json_merge(default_value, user_values)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Debug)]
|
||||
pub enum ItemEvent {
|
||||
CloseItem,
|
||||
|
|
|
@ -3,14 +3,16 @@ mod dragged_item_receiver;
|
|||
use super::{ItemHandle, SplitDirection};
|
||||
pub use crate::toolbar::Toolbar;
|
||||
use crate::{
|
||||
item::WeakItemHandle, notify_of_new_dock, AutosaveSetting, Item, NewCenterTerminal, NewFile,
|
||||
NewSearch, ToggleZoom, Workspace, WorkspaceSettings,
|
||||
item::{ItemSettings, WeakItemHandle},
|
||||
notify_of_new_dock, AutosaveSetting, Item, NewCenterTerminal, NewFile, NewSearch, ToggleZoom,
|
||||
Workspace, WorkspaceSettings,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use collections::{HashMap, HashSet, VecDeque};
|
||||
use context_menu::{ContextMenu, ContextMenuItem};
|
||||
use drag_and_drop::{DragAndDrop, Draggable};
|
||||
use dragged_item_receiver::dragged_item_receiver;
|
||||
use fs::repository::GitFileStatus;
|
||||
use futures::StreamExt;
|
||||
use gpui::{
|
||||
actions,
|
||||
|
@ -866,6 +868,7 @@ impl Pane {
|
|||
.paths_by_item
|
||||
.get(&item.id())
|
||||
.and_then(|(_, abs_path)| abs_path.clone());
|
||||
|
||||
self.nav_history
|
||||
.0
|
||||
.borrow_mut()
|
||||
|
@ -1157,6 +1160,11 @@ impl Pane {
|
|||
.zip(self.tab_details(cx))
|
||||
.enumerate()
|
||||
{
|
||||
let git_status = item
|
||||
.project_path(cx)
|
||||
.and_then(|path| self.project.read(cx).entry_for_path(&path, cx))
|
||||
.and_then(|entry| entry.git_status());
|
||||
|
||||
let detail = if detail == 0 { None } else { Some(detail) };
|
||||
let tab_active = ix == self.active_item_index;
|
||||
|
||||
|
@ -1174,9 +1182,21 @@ impl Pane {
|
|||
let tab_tooltip_text =
|
||||
item.tab_tooltip_text(cx).map(|text| text.into_owned());
|
||||
|
||||
let mut tab_style = theme
|
||||
.workspace
|
||||
.tab_bar
|
||||
.tab_style(pane_active, tab_active)
|
||||
.clone();
|
||||
let should_show_status = settings::get::<ItemSettings>(cx).git_status;
|
||||
if should_show_status && git_status != None {
|
||||
tab_style.label.text.color = match git_status.unwrap() {
|
||||
GitFileStatus::Added => tab_style.git.inserted,
|
||||
GitFileStatus::Modified => tab_style.git.modified,
|
||||
GitFileStatus::Conflict => tab_style.git.conflict,
|
||||
};
|
||||
}
|
||||
|
||||
move |mouse_state, cx| {
|
||||
let tab_style =
|
||||
theme.workspace.tab_bar.tab_style(pane_active, tab_active);
|
||||
let hovered = mouse_state.hovered();
|
||||
|
||||
enum Tab {}
|
||||
|
@ -1188,7 +1208,7 @@ impl Pane {
|
|||
ix == 0,
|
||||
detail,
|
||||
hovered,
|
||||
tab_style,
|
||||
&tab_style,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
|
@ -1350,81 +1370,94 @@ impl Pane {
|
|||
container.border.left = false;
|
||||
}
|
||||
|
||||
Flex::row()
|
||||
.with_child({
|
||||
let diameter = 7.0;
|
||||
let icon_color = if item.has_conflict(cx) {
|
||||
Some(tab_style.icon_conflict)
|
||||
} else if item.is_dirty(cx) {
|
||||
Some(tab_style.icon_dirty)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let buffer_jewel_element = {
|
||||
let diameter = 7.0;
|
||||
let icon_color = if item.has_conflict(cx) {
|
||||
Some(tab_style.icon_conflict)
|
||||
} else if item.is_dirty(cx) {
|
||||
Some(tab_style.icon_dirty)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Canvas::new(move |scene, bounds, _, _, _| {
|
||||
if let Some(color) = icon_color {
|
||||
let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
|
||||
scene.push_quad(Quad {
|
||||
bounds: square,
|
||||
background: Some(color),
|
||||
border: Default::default(),
|
||||
corner_radius: diameter / 2.,
|
||||
});
|
||||
}
|
||||
})
|
||||
.constrained()
|
||||
.with_width(diameter)
|
||||
.with_height(diameter)
|
||||
.aligned()
|
||||
Canvas::new(move |scene, bounds, _, _, _| {
|
||||
if let Some(color) = icon_color {
|
||||
let square = RectF::new(bounds.origin(), vec2f(diameter, diameter));
|
||||
scene.push_quad(Quad {
|
||||
bounds: square,
|
||||
background: Some(color),
|
||||
border: Default::default(),
|
||||
corner_radius: diameter / 2.,
|
||||
});
|
||||
}
|
||||
})
|
||||
.with_child(title.aligned().contained().with_style(ContainerStyle {
|
||||
margin: Margin {
|
||||
left: tab_style.spacing,
|
||||
right: tab_style.spacing,
|
||||
..Default::default()
|
||||
},
|
||||
.constrained()
|
||||
.with_width(diameter)
|
||||
.with_height(diameter)
|
||||
.aligned()
|
||||
};
|
||||
|
||||
let title_element = title.aligned().contained().with_style(ContainerStyle {
|
||||
margin: Margin {
|
||||
left: tab_style.spacing,
|
||||
right: tab_style.spacing,
|
||||
..Default::default()
|
||||
}))
|
||||
.with_child(
|
||||
if hovered {
|
||||
let item_id = item.id();
|
||||
enum TabCloseButton {}
|
||||
let icon = Svg::new("icons/x_mark_8.svg");
|
||||
MouseEventHandler::<TabCloseButton, _>::new(item_id, cx, |mouse_state, _| {
|
||||
if mouse_state.hovered() {
|
||||
icon.with_color(tab_style.icon_close_active)
|
||||
} else {
|
||||
icon.with_color(tab_style.icon_close)
|
||||
}
|
||||
})
|
||||
.with_padding(Padding::uniform(4.))
|
||||
.with_cursor_style(CursorStyle::PointingHand)
|
||||
.on_click(MouseButton::Left, {
|
||||
let pane = pane.clone();
|
||||
move |_, _, cx| {
|
||||
let pane = pane.clone();
|
||||
cx.window_context().defer(move |cx| {
|
||||
if let Some(pane) = pane.upgrade(cx) {
|
||||
pane.update(cx, |pane, cx| {
|
||||
pane.close_item_by_id(item_id, cx).detach_and_log_err(cx);
|
||||
});
|
||||
}
|
||||
},
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
let close_element = if hovered {
|
||||
let item_id = item.id();
|
||||
enum TabCloseButton {}
|
||||
let icon = Svg::new("icons/x_mark_8.svg");
|
||||
MouseEventHandler::<TabCloseButton, _>::new(item_id, cx, |mouse_state, _| {
|
||||
if mouse_state.hovered() {
|
||||
icon.with_color(tab_style.icon_close_active)
|
||||
} else {
|
||||
icon.with_color(tab_style.icon_close)
|
||||
}
|
||||
})
|
||||
.with_padding(Padding::uniform(4.))
|
||||
.with_cursor_style(CursorStyle::PointingHand)
|
||||
.on_click(MouseButton::Left, {
|
||||
let pane = pane.clone();
|
||||
move |_, _, cx| {
|
||||
let pane = pane.clone();
|
||||
cx.window_context().defer(move |cx| {
|
||||
if let Some(pane) = pane.upgrade(cx) {
|
||||
pane.update(cx, |pane, cx| {
|
||||
pane.close_item_by_id(item_id, cx).detach_and_log_err(cx);
|
||||
});
|
||||
}
|
||||
})
|
||||
.into_any_named("close-tab-icon")
|
||||
.constrained()
|
||||
} else {
|
||||
Empty::new().constrained()
|
||||
});
|
||||
}
|
||||
.with_width(tab_style.close_icon_width)
|
||||
.aligned(),
|
||||
)
|
||||
.contained()
|
||||
.with_style(container)
|
||||
})
|
||||
.into_any_named("close-tab-icon")
|
||||
.constrained()
|
||||
.with_height(tab_style.height)
|
||||
.into_any()
|
||||
} else {
|
||||
Empty::new().constrained()
|
||||
}
|
||||
.with_width(tab_style.close_icon_width)
|
||||
.aligned();
|
||||
|
||||
let close_right = settings::get::<ItemSettings>(cx).close_position.right();
|
||||
|
||||
if close_right {
|
||||
Flex::row()
|
||||
.with_child(buffer_jewel_element)
|
||||
.with_child(title_element)
|
||||
.with_child(close_element)
|
||||
} else {
|
||||
Flex::row()
|
||||
.with_child(close_element)
|
||||
.with_child(title_element)
|
||||
.with_child(buffer_jewel_element)
|
||||
}
|
||||
.contained()
|
||||
.with_style(container)
|
||||
.constrained()
|
||||
.with_height(tab_style.height)
|
||||
.into_any()
|
||||
}
|
||||
|
||||
pub fn render_tab_bar_button<
|
||||
|
|
|
@ -203,6 +203,7 @@ pub type WorkspaceId = i64;
|
|||
|
||||
pub fn init_settings(cx: &mut AppContext) {
|
||||
settings::register::<WorkspaceSettings>(cx);
|
||||
settings::register::<item::ItemSettings>(cx);
|
||||
}
|
||||
|
||||
pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue