feat(workspace): show git status on editor tabs

This commit is contained in:
Alex Viscreanu 2023-07-17 18:48:57 +02:00
parent 10a1df3faa
commit 6793d4b6b8
No known key found for this signature in database
6 changed files with 74 additions and 7 deletions

View file

@ -128,6 +128,10 @@
// 4. Save when idle for a certain amount of time: // 4. Save when idle for a certain amount of time:
// "autosave": { "after_delay": {"milliseconds": 500} }, // "autosave": { "after_delay": {"milliseconds": 500} },
"autosave": "off", "autosave": "off",
// Color tab titles based on the git status of the buffer.
"tabs": {
"git_status": false
},
// Whether or not to remove any trailing whitespace from lines of a buffer // Whether or not to remove any trailing whitespace from lines of a buffer
// before saving it. // before saving it.
"remove_trailing_whitespace_on_save": true, "remove_trailing_whitespace_on_save": true,

View file

@ -350,6 +350,7 @@ pub struct Tab {
pub icon_close_active: Color, pub icon_close_active: Color,
pub icon_dirty: Color, pub icon_dirty: Color,
pub icon_conflict: Color, pub icon_conflict: Color,
pub git: GitProjectStatus,
} }
#[derive(Clone, Deserialize, Default, JsonSchema)] #[derive(Clone, Deserialize, Default, JsonSchema)]
@ -722,12 +723,12 @@ pub struct Scrollbar {
pub thumb: ContainerStyle, pub thumb: ContainerStyle,
pub width: f32, pub width: f32,
pub min_height_factor: f32, pub min_height_factor: f32,
pub git: GitDiffColors, pub git: FileGitDiffColors,
pub selections: Color, pub selections: Color,
} }
#[derive(Clone, Deserialize, Default, JsonSchema)] #[derive(Clone, Deserialize, Default, JsonSchema)]
pub struct GitDiffColors { pub struct FileGitDiffColors {
pub inserted: Color, pub inserted: Color,
pub modified: Color, pub modified: Color,
pub deleted: Color, pub deleted: Color,

View file

@ -10,6 +10,9 @@ use gpui::{
ViewContext, ViewHandle, WeakViewHandle, WindowContext, ViewContext, ViewHandle, WeakViewHandle, WindowContext,
}; };
use project::{Project, ProjectEntryId, ProjectPath}; use project::{Project, ProjectEntryId, ProjectPath};
use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
use settings::Setting;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{ use std::{
any::{Any, TypeId}, any::{Any, TypeId},
@ -27,6 +30,30 @@ use std::{
}; };
use theme::Theme; use theme::Theme;
#[derive(Deserialize)]
pub struct ItemSettings {
pub git_status: bool,
}
#[derive(Clone, Default, Serialize, Deserialize, JsonSchema)]
pub struct ItemSettingsContent {
git_status: Option<bool>,
}
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)] #[derive(Eq, PartialEq, Hash, Debug)]
pub enum ItemEvent { pub enum ItemEvent {
CloseItem, CloseItem,

View file

@ -3,14 +3,16 @@ mod dragged_item_receiver;
use super::{ItemHandle, SplitDirection}; use super::{ItemHandle, SplitDirection};
pub use crate::toolbar::Toolbar; pub use crate::toolbar::Toolbar;
use crate::{ use crate::{
item::WeakItemHandle, notify_of_new_dock, AutosaveSetting, Item, NewCenterTerminal, NewFile, item::{ItemSettings, WeakItemHandle},
NewSearch, ToggleZoom, Workspace, WorkspaceSettings, notify_of_new_dock, AutosaveSetting, Item, NewCenterTerminal, NewFile, NewSearch, ToggleZoom,
Workspace, WorkspaceSettings,
}; };
use anyhow::Result; use anyhow::Result;
use collections::{HashMap, HashSet, VecDeque}; use collections::{HashMap, HashSet, VecDeque};
use context_menu::{ContextMenu, ContextMenuItem}; use context_menu::{ContextMenu, ContextMenuItem};
use drag_and_drop::{DragAndDrop, Draggable}; use drag_and_drop::{DragAndDrop, Draggable};
use dragged_item_receiver::dragged_item_receiver; use dragged_item_receiver::dragged_item_receiver;
use fs::repository::GitFileStatus;
use futures::StreamExt; use futures::StreamExt;
use gpui::{ use gpui::{
actions, actions,
@ -866,6 +868,7 @@ impl Pane {
.paths_by_item .paths_by_item
.get(&item.id()) .get(&item.id())
.and_then(|(_, abs_path)| abs_path.clone()); .and_then(|(_, abs_path)| abs_path.clone());
self.nav_history self.nav_history
.0 .0
.borrow_mut() .borrow_mut()
@ -1157,6 +1160,11 @@ impl Pane {
.zip(self.tab_details(cx)) .zip(self.tab_details(cx))
.enumerate() .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 detail = if detail == 0 { None } else { Some(detail) };
let tab_active = ix == self.active_item_index; let tab_active = ix == self.active_item_index;
@ -1174,9 +1182,21 @@ impl Pane {
let tab_tooltip_text = let tab_tooltip_text =
item.tab_tooltip_text(cx).map(|text| text.into_owned()); 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| { move |mouse_state, cx| {
let tab_style =
theme.workspace.tab_bar.tab_style(pane_active, tab_active);
let hovered = mouse_state.hovered(); let hovered = mouse_state.hovered();
enum Tab {} enum Tab {}
@ -1188,7 +1208,7 @@ impl Pane {
ix == 0, ix == 0,
detail, detail,
hovered, hovered,
tab_style, &tab_style,
cx, cx,
) )
}) })

View file

@ -203,6 +203,7 @@ pub type WorkspaceId = i64;
pub fn init_settings(cx: &mut AppContext) { pub fn init_settings(cx: &mut AppContext) {
settings::register::<WorkspaceSettings>(cx); settings::register::<WorkspaceSettings>(cx);
settings::register::<item::ItemSettings>(cx);
} }
pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) { pub fn init(app_state: Arc<AppState>, cx: &mut AppContext) {

View file

@ -6,6 +6,8 @@ import { useTheme } from "../common"
export default function tab_bar(): any { export default function tab_bar(): any {
const theme = useTheme() const theme = useTheme()
const { is_light } = theme
const height = 32 const height = 32
const active_layer = theme.highest const active_layer = theme.highest
@ -38,6 +40,18 @@ export default function tab_bar(): any {
icon_conflict: foreground(layer, "warning"), icon_conflict: foreground(layer, "warning"),
icon_dirty: foreground(layer, "accent"), icon_dirty: foreground(layer, "accent"),
git: {
modified: is_light
? theme.ramps.yellow(0.6).hex()
: theme.ramps.yellow(0.5).hex(),
inserted: is_light
? theme.ramps.green(0.45).hex()
: theme.ramps.green(0.5).hex(),
conflict: is_light
? theme.ramps.red(0.6).hex()
: theme.ramps.red(0.5).hex(),
},
// When two tabs of the same name are open, a label appears next to them // When two tabs of the same name are open, a label appears next to them
description: { description: {
margin: { left: 8 }, margin: { left: 8 },