1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
use ratatui::{
layout::Rect,
style::{Color, Modifier, Style},
text::{Line, Span},
widgets::{Block, Borders, Tabs},
Frame,
};
/// Renders a tab bar showing all open buffers
pub struct TabBarWidget {
/// Current buffer index
current_index: usize,
/// List of buffer names
buffer_names: Vec<String>,
/// Whether to show Alt+N shortcuts
show_shortcuts: bool,
}
impl TabBarWidget {
#[must_use]
pub fn new(current_index: usize, buffer_names: Vec<String>) -> Self {
Self {
current_index,
buffer_names,
show_shortcuts: true,
}
}
/// Set whether to show Alt+N shortcuts
#[must_use]
pub fn with_shortcuts(mut self, show: bool) -> Self {
self.show_shortcuts = show;
self
}
/// Render the tab bar
pub fn render(&self, f: &mut Frame, area: Rect) {
// Always render tab bar to maintain consistent layout
// Even with one buffer, showing the tab provides visual consistency
// Create tab titles with optional shortcuts
let titles: Vec<Line> = self
.buffer_names
.iter()
.enumerate()
.map(|(i, name)| {
let mut spans = vec![];
// Add shortcut indicator if enabled and within Alt+1-9 range
if self.show_shortcuts && i < 9 {
spans.push(Span::styled(
format!("{}:", i + 1),
Style::default()
.fg(Color::DarkGray)
.add_modifier(Modifier::DIM),
));
}
// Truncate long buffer names
let display_name = if name.len() > 20 {
format!("{}...", &name[..17])
} else {
name.clone()
};
spans.push(Span::raw(display_name));
Line::from(spans)
})
.collect();
let tabs = Tabs::new(titles)
.block(
Block::default()
.borders(Borders::BOTTOM)
.border_style(Style::default().fg(Color::DarkGray)),
)
.select(self.current_index)
.style(Style::default().fg(Color::Gray))
.highlight_style(
Style::default()
.fg(Color::White)
.add_modifier(Modifier::BOLD)
.bg(Color::DarkGray),
)
.divider(Span::styled(" │ ", Style::default().fg(Color::DarkGray)));
f.render_widget(tabs, area);
}
/// Calculate the height needed for the tab bar
#[must_use]
pub fn height(&self) -> u16 {
// Always reserve space for tab bar to maintain consistent layout
2 // Tab bar with border
}
}
/// Helper function to create and render a tab bar in one call
pub fn render_tab_bar(f: &mut Frame, area: Rect, current_index: usize, buffer_names: Vec<String>) {
let widget = TabBarWidget::new(current_index, buffer_names);
widget.render(f, area);
}