style: refine tab bar appearance
This commit is contained in:
+1
-1
@@ -218,7 +218,7 @@ Use `:tab.new` to open the current buffer in a new, focused tab with one pane. E
|
|||||||
| `:tab.close` | `config.core.tab.close` | Close the current tab and all its panes, protecting unsaved changes |
|
| `:tab.close` | `config.core.tab.close` | Close the current tab and all its panes, protecting unsaved changes |
|
||||||
| `:tab.force_close` | `config.core.tab.force_close` | Explicitly discard exclusively displayed edits and close the tab |
|
| `:tab.force_close` | `config.core.tab.force_close` | Explicitly discard exclusively displayed edits and close the tab |
|
||||||
|
|
||||||
Multiple tabs show a top row with numbered filenames, dirty markers, and an active-tab highlight. Narrow terminals keep the active tab visible. New/close actions have no default keybinding; for example, `config.bind "leader t", config.core.tab.new`.
|
Multiple tabs show a single top row with padded numbered filenames, subtle separators, and dirty markers. The active tab uses bold, underlined accent text; the row keeps the terminal's background instead of painting a full-width band. Narrow terminals keep the active tab visible. New/close actions have no default keybinding; for example, `config.bind "leader t", config.core.tab.new`.
|
||||||
|
|
||||||
Closing a tab refuses dirty buffers whose final displayed owner would disappear, including a comparison's working and return buffers. Buffers displayed in another tab remain open with their edits, even on force-close. Other hidden buffers remain loaded. Closing the last tab quits only if every open buffer is clean; force-close quits without saving.
|
Closing a tab refuses dirty buffers whose final displayed owner would disappear, including a comparison's working and return buffers. Buffers displayed in another tab remain open with their edits, even on force-close. Other hidden buffers remain loaded. Closing the last tab quits only if every open buffer is clean; force-close quits without saving.
|
||||||
|
|
||||||
|
|||||||
+17
-18
@@ -1040,21 +1040,28 @@ fn draw_tab_bar(frame: &mut Frame, editor: &Editor, area: Rect) -> Rect {
|
|||||||
.collect();
|
.collect();
|
||||||
let active = editor.tab_index();
|
let active = editor.tab_index();
|
||||||
let mut first = active;
|
let mut first = active;
|
||||||
let mut width = labels[active].width();
|
let padding = u16::from(bar.width > 1);
|
||||||
while first > 0 && width + labels[first - 1].width() <= usize::from(bar.width) {
|
let mut width = labels[active].width() + usize::from(padding);
|
||||||
|
while first > 0 && width + 2 + labels[first - 1].width() <= usize::from(bar.width) {
|
||||||
first -= 1;
|
first -= 1;
|
||||||
width += labels[first].width();
|
width += 2 + labels[first].width();
|
||||||
}
|
}
|
||||||
let inactive = Style::default().fg(Color::Gray).bg(Color::DarkGray);
|
let inactive = Style::default().fg(Color::Gray);
|
||||||
frame.render_widget(Paragraph::new("").style(inactive), bar);
|
let mut x = bar.x + padding;
|
||||||
let mut x = bar.x;
|
|
||||||
for (index, label) in labels.iter().enumerate().skip(first) {
|
for (index, label) in labels.iter().enumerate().skip(first) {
|
||||||
|
if index != first {
|
||||||
|
let width = 2.min(bar.right() - x);
|
||||||
|
frame.render_widget(
|
||||||
|
Paragraph::new("│ ").style(Style::default().fg(Color::DarkGray)),
|
||||||
|
Rect::new(x, bar.y, width, 1),
|
||||||
|
);
|
||||||
|
x += width;
|
||||||
|
}
|
||||||
let width = label.width().min(usize::from(bar.right() - x)) as u16;
|
let width = label.width().min(usize::from(bar.right() - x)) as u16;
|
||||||
let style = if index == active {
|
let style = if index == active {
|
||||||
Style::default()
|
Style::default()
|
||||||
.fg(Color::Black)
|
.fg(Color::Cyan)
|
||||||
.bg(Color::Cyan)
|
.add_modifier(Modifier::BOLD | Modifier::UNDERLINED)
|
||||||
.add_modifier(Modifier::BOLD)
|
|
||||||
} else {
|
} else {
|
||||||
inactive
|
inactive
|
||||||
};
|
};
|
||||||
@@ -5189,12 +5196,6 @@ mod tests {
|
|||||||
let titles = pane_screen(&terminal, Rect::new(0, 0, 80, 1));
|
let titles = pane_screen(&terminal, Rect::new(0, 0, 80, 1));
|
||||||
assert!(titles.contains("1 a�name.txt [+]"), "{titles}");
|
assert!(titles.contains("1 a�name.txt [+]"), "{titles}");
|
||||||
assert!(titles.contains("2 a�name.txt [+]"), "{titles}");
|
assert!(titles.contains("2 a�name.txt [+]"), "{titles}");
|
||||||
let active_x = display_column(&titles[..titles.find("2 a�name.txt").unwrap()], usize::MAX);
|
|
||||||
assert_eq!(terminal.backend().buffer()[(0, 0)].bg, Color::DarkGray);
|
|
||||||
assert_eq!(
|
|
||||||
terminal.backend().buffer()[(active_x as u16, 0)].bg,
|
|
||||||
Color::Cyan
|
|
||||||
);
|
|
||||||
assert_eq!(views.document.geometry.unwrap().1.y, 1);
|
assert_eq!(views.document.geometry.unwrap().1.y, 1);
|
||||||
assert!(terminal.get_cursor_position().unwrap().y >= 1);
|
assert!(terminal.get_cursor_position().unwrap().y >= 1);
|
||||||
assert!(pane_screen(&terminal, views.rects[0].1).contains("changed DOCUMENT"));
|
assert!(pane_screen(&terminal, views.rects[0].1).contains("changed DOCUMENT"));
|
||||||
@@ -5231,9 +5232,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
if width > 0 && height > 0 {
|
if width > 0 && height > 0 {
|
||||||
let title = pane_screen(&terminal, Rect::new(0, 0, width, 1));
|
let title = pane_screen(&terminal, Rect::new(0, 0, width, 1));
|
||||||
let expected: String = "3 active.txt".chars().take(usize::from(width)).collect();
|
assert!(title.trim_start().starts_with('3'), "{title}");
|
||||||
assert_eq!(title, expected);
|
|
||||||
assert_eq!(terminal.backend().buffer()[(0, 0)].bg, Color::Cyan);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user