fix(tabs): restore 1.7 status alignment and unclipped glyphs

This commit is contained in:
kuddev committed 2026-09-15 12:46:20 +08:00
1 parent d426de4ae1
commit 036d57a25c
2 files changed
+132 -32

No files matched your search

+124 -16
View File
@@ -53,6 +53,31 @@ pub(super) fn resting_activity(
}
impl NebulaWorkspace {
pub(super) fn shell_status_label(
tag: SharedString,
family: SharedString,
size_px: f32,
color: gpui::Hsla,
) -> gpui::Div {
// As in 1.7, short labels keep their intrinsic width and align right in
// the status row. Only a long label is clipped to the available space.
div()
.max_w_full()
.min_w_0()
.truncate()
.font_family(family)
.text_size(px(size_px))
.font_weight(FontWeight::NORMAL)
.text_color(color)
.child(tag)
}
pub(super) fn tab_status_slot(width: f32) -> gpui::Div {
// Nerd Font ink can extend beyond its advance. Keep the 1.7 slot
// unclipped; the enclosing tab still clips at its own outer boundary.
div().relative().w(px(width)).h_full().flex_shrink_0()
}
/// Reserve the shaped shell label's width, capped to leave room for the title.
pub(super) fn shell_status_width(
window: &Window,
@@ -356,16 +381,13 @@ impl NebulaWorkspace {
.into_any_element(),
),
SidebarActivity::Idle => shell_tag.map(|tag| {
div()
.w_full()
.min_w_0()
.truncate()
.font_family(chrome_family.clone())
.text_size(px(label_px * SIDEBAR_TAG_SCALE))
.font_weight(FontWeight::NORMAL)
.text_color(status_color)
.child(tag)
.into_any_element()
Self::shell_status_label(
tag,
chrome_family.clone(),
label_px * SIDEBAR_TAG_SCALE,
status_color,
)
.into_any_element()
}),
};
// 三类行位移(旧壳 tab_drag_draw_y 的语义):被拖行骑指针,
@@ -565,12 +587,7 @@ impl NebulaWorkspace {
)
})
.child(
div()
.relative()
.w(px(status_width))
.h_full()
.overflow_hidden()
.flex_shrink_0()
Self::tab_status_slot(status_width)
.when_some(resting_status, |slot, status| {
slot.child(
h_flex()
@@ -1090,6 +1107,97 @@ impl NebulaWorkspace {
mod tests {
use super::*;
#[cfg(feature = "gpui-test-support")]
mod layout {
use super::*;
use std::cell::RefCell;
use std::rc::Rc;
struct StatusProbe {
label: SharedString,
font_size: f32,
mask: Rc<RefCell<Option<Bounds<Pixels>>>>,
}
impl Render for StatusProbe {
fn render(
&mut self,
_window: &mut Window,
_cx: &mut Context<Self>,
) -> impl IntoElement {
let mask = self.mask.clone();
h_flex()
.id("status-probe-row")
.debug_selector(|| "status-probe-row".to_owned())
.w(px(200.0))
.h(px(TAB_ROW_H))
.px_2()
.overflow_hidden()
.child(div().flex_1())
.child(
NebulaWorkspace::tab_status_slot(TAB_STATUS_SLOT_W)
.id("status-probe-slot")
.debug_selector(|| "status-probe-slot".to_owned())
.child(
h_flex().absolute().inset_0().justify_end().items_center().child(
NebulaWorkspace::shell_status_label(
self.label.clone(),
".SystemUIFont".into(),
self.font_size,
gpui::black(),
)
.id("status-probe-label")
.debug_selector(|| "status-probe-label".to_owned()),
),
)
.child(
canvas(
|_, _, _| {},
move |_, _, window, _| {
*mask.borrow_mut() = Some(window.content_mask().bounds);
},
)
.absolute()
.size_full(),
),
)
}
}
#[gpui::test]
fn short_shells_align_right_long_shells_fit_and_glyph_ink_keeps_row_padding(
cx: &mut gpui::TestAppContext,
) {
cx.update(gpui_component::init);
for font_size in [12.0, 15.0, 20.0] {
for label in ["sh", "debian", "a-very-long-shell-distribution-name"] {
let mask = Rc::new(RefCell::new(None));
let recorded = mask.clone();
let (_, visual) = cx.add_window_view(|_, _| StatusProbe {
label: label.into(),
font_size,
mask,
});
let row = visual.debug_bounds("status-probe-row").unwrap();
let slot = visual.debug_bounds("status-probe-slot").unwrap();
let text = visual.debug_bounds("status-probe-label").unwrap();
assert!(text.size.width <= slot.size.width);
assert_eq!(
text.right(),
slot.right(),
"shell labels retain the 1.7 right edge"
);
if label == "sh" {
assert!(text.size.width < slot.size.width, "short labels stay intrinsic");
}
let clip = recorded.borrow().expect("status paint mask");
assert!(clip.right() > slot.right(), "glyph overhang must retain row padding");
assert!(clip.right() <= row.right(), "the outer row still clips overflow");
}
}
}
}
#[test]
fn finished_dot_is_an_event_so_the_tab_you_are_watching_never_shows_it() {
// 你正盯着 agent 跑完:那个点在你眼前亮起没有任何信息量。
@@ -238,16 +238,13 @@ impl NebulaWorkspace {
.into_any_element(),
),
SidebarActivity::Idle => shell_tag.map(|tag| {
div()
.w_full()
.min_w_0()
.truncate()
.font_family(chrome_family.clone())
.text_size(px(label_px * 0.8))
.font_weight(FontWeight::NORMAL)
.text_color(status_color)
.child(tag)
.into_any_element()
Self::shell_status_label(
tag,
chrome_family.clone(),
label_px * 0.8,
status_color,
)
.into_any_element()
}),
};
let strip = color.map(|color| gpui::Rgba {
@@ -462,12 +459,7 @@ impl NebulaWorkspace {
)
})
.child(
div()
.relative()
.w(px(status_width))
.h_full()
.overflow_hidden()
.flex_shrink_0()
Self::tab_status_slot(status_width)
.when_some(resting_status, |slot, status| {
slot.child(
h_flex()