feat(workspace): show git status on editor tabs
This commit is contained in:
parent
10a1df3faa
commit
6793d4b6b8
6 changed files with 74 additions and 7 deletions
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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 },
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue