Skip to content

Commit dd98ff4

Browse files
datlechinclaude
andcommitted
refactor(linux): content-sized tabs + non-redundant tooltips
- AdwTabBar: expand_tabs(true) → expand_tabs(false). Tabs now size to content; AdwTabBar handles overflow natively. Avoids the 5-tabs-fill- bar / 15-tabs-unreadable-width tradeoff. Matches TablePlus, DBeaver, DataGrip. - Tab tooltips: only set when they add information beyond the visible title. Browse tab labelled `users` in single-schema mode now hovers to `public.users`; labelled `public.users` (multi-schema) shows no tooltip (was duplicating the title and overlapping the data grid). Editor tabs: tooltip = 200-char preview only when label is truncated. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
1 parent e229e9a commit dd98ff4

1 file changed

Lines changed: 44 additions & 5 deletions

File tree

linux/crates/app/src/ui/app/workspace_tabs.rs

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,13 @@ impl App {
3333

3434
fn build_workspace_root(&mut self, sender: ComponentSender<Self>) {
3535
let tab_view = adw::TabView::new();
36+
// Content-sized tabs: with expand_tabs(true), 5 tabs already span the
37+
// whole bar and 15+ would compress to unreadable widths. Matches
38+
// TablePlus / DBeaver / DataGrip; AdwTabBar handles overflow natively.
3639
let tab_bar = adw::TabBar::builder()
3740
.view(&tab_view)
3841
.autohide(false)
39-
.expand_tabs(true)
42+
.expand_tabs(false)
4043
.build();
4144

4245
let overview_button = adw::TabButton::builder()
@@ -123,7 +126,8 @@ impl App {
123126
.count();
124127
let label = default_editor_tab_label(editor_count + 1);
125128
page.set_title(&label);
126-
page.set_tooltip(&label);
129+
// Empty query → no tooltip; tooltip will be set on first edit
130+
// via on_editor_tab_query_changed.
127131
write_workspace_tab_id(&page, tab_id);
128132
let slot = EditorTabSlot {
129133
id: tab_id,
@@ -317,7 +321,9 @@ impl App {
317321
let page = tab_view.append(controller.widget());
318322
let label = qualified_browse_tab_label(self.sidebar_schemas_distinct(), schema.as_deref(), &table);
319323
page.set_title(&label);
320-
page.set_tooltip(&label);
324+
if let Some(tip) = browse_tab_tooltip(schema.as_deref(), &table, &label) {
325+
page.set_tooltip(&tip);
326+
}
321327
write_workspace_tab_id(&page, tab_id);
322328

323329
let slot = BrowseTabSlot {
@@ -359,7 +365,9 @@ impl App {
359365
false => derive_tab_label(&query),
360366
};
361367
page.set_title(&label);
362-
page.set_tooltip(&label);
368+
if let Some(tip) = editor_tab_tooltip(&query, &label) {
369+
page.set_tooltip(&tip);
370+
}
363371
write_workspace_tab_id(&page, tab_id);
364372

365373
let slot = EditorTabSlot {
@@ -632,7 +640,10 @@ impl App {
632640
};
633641
if let Some(WorkspaceTab::Editor(slot)) = self.workspace_tabs.borrow_mut().get_mut(&id) {
634642
slot.page.set_title(&label);
635-
slot.page.set_tooltip(&label);
643+
// Pass empty when no extra info to clear any prior tooltip;
644+
// libadwaita treats empty-string as no tooltip.
645+
let tooltip = editor_tab_tooltip(&query, &label).unwrap_or_default();
646+
slot.page.set_tooltip(&tooltip);
636647
slot.query = query;
637648
}
638649
self.persist_workspace_state();
@@ -681,3 +692,31 @@ fn qualified_browse_tab_label(schemas_count: usize, schema: Option<&str>, table:
681692
fn default_editor_tab_label(n: usize) -> String {
682693
crate::tr!("Query {n}").replace("{n}", &n.to_string())
683694
}
695+
696+
/// Returns a tooltip for a Browse tab, but only when it would add info
697+
/// beyond the visible label. When the label is already
698+
/// `schema.table`, or there is no schema, the tooltip would just
699+
/// duplicate the tab title and we skip it.
700+
fn browse_tab_tooltip(schema: Option<&str>, table: &str, label: &str) -> Option<String> {
701+
let s = schema?;
702+
let qualified = format!("{s}.{table}");
703+
if qualified == label { None } else { Some(qualified) }
704+
}
705+
706+
/// Returns a tooltip for an Editor tab. Empty for blank queries; for
707+
/// non-empty queries, a 200-char preview — but only when distinct from
708+
/// the (truncated) label, so non-truncated labels don't get a redundant
709+
/// hover popup.
710+
fn editor_tab_tooltip(query: &str, label: &str) -> Option<String> {
711+
let q = query.trim();
712+
if q.is_empty() {
713+
return None;
714+
}
715+
let preview: String = q.chars().take(200).collect();
716+
let preview = if q.chars().count() > 200 {
717+
format!("{preview}…")
718+
} else {
719+
preview
720+
};
721+
if preview == label { None } else { Some(preview) }
722+
}

0 commit comments

Comments
 (0)