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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
use crate::{line::tab_separator, LinePart};
use ansi_term::{ANSIString, ANSIStrings};
use unicode_width::UnicodeWidthStr;
use zellij_tile::prelude::*;
use zellij_tile_utils::style;
fn cursors<'a>(
focused_clients: &'a [ClientId],
multiplayer_colors: MultiplayerColors,
) -> (Vec<ANSIString<'a>>, usize) {
// cursor section, text length
let mut len = 0;
let mut cursors = vec![];
for client_id in focused_clients.iter() {
if let Some(color) = client_id_to_colors(*client_id, multiplayer_colors) {
cursors.push(style!(color.1, color.0).paint(" "));
len += 1;
}
}
(cursors, len)
}
pub fn render_tab(
text: String,
tab: &TabInfo,
is_alternate_tab: bool,
is_hovered: bool,
palette: Styling,
separator: &str,
) -> LinePart {
let focused_clients = tab.other_focused_clients.as_slice();
let separator_width = separator.width();
let alternate_tab_color = if is_alternate_tab {
palette.ribbon_unselected.emphasis_1
} else {
palette.ribbon_unselected.background
};
let background_color = if tab.active {
palette.ribbon_selected.background
} else if is_hovered {
palette.ribbon_unselected.emphasis_1
} else if is_alternate_tab {
alternate_tab_color
} else {
palette.ribbon_unselected.background
};
let foreground_color = if tab.is_flashing_bell {
if tab.active {
palette.ribbon_selected.emphasis_3
} else {
palette.ribbon_unselected.emphasis_3
}
} else if tab.active {
palette.ribbon_selected.base
} else {
palette.ribbon_unselected.base
};
let separator_fill_color = palette.text_unselected.background;
let left_separator = style!(separator_fill_color, background_color).paint(separator);
let mut tab_text_len = text.width() + (separator_width * 2) + 2; // +2 for padding
let tab_styled_text = style!(foreground_color, background_color)
.bold()
.paint(format!(" {} ", text));
let right_separator = style!(background_color, separator_fill_color).paint(separator);
let tab_styled_text = if !focused_clients.is_empty() {
let (cursor_section, extra_length) =
cursors(focused_clients, palette.multiplayer_user_colors);
tab_text_len += extra_length + 2; // 2 for cursor_beginning and cursor_end
let mut s = String::new();
let cursor_beginning = style!(foreground_color, background_color)
.bold()
.paint("[")
.to_string();
let cursor_section = ANSIStrings(&cursor_section).to_string();
let cursor_end = style!(foreground_color, background_color)
.bold()
.paint("]")
.to_string();
s.push_str(&left_separator.to_string());
s.push_str(&tab_styled_text.to_string());
s.push_str(&cursor_beginning);
s.push_str(&cursor_section);
s.push_str(&cursor_end);
s.push_str(&right_separator.to_string());
s
} else {
ANSIStrings(&[left_separator, tab_styled_text, right_separator]).to_string()
};
LinePart {
part: tab_styled_text,
len: tab_text_len,
tab_index: Some(tab.position),
}
}
pub fn tab_style(
mut tabname: String,
tab: &TabInfo,
mut is_alternate_tab: bool,
is_hovered: bool,
palette: Styling,
capabilities: PluginCapabilities,
) -> LinePart {
let separator = tab_separator(capabilities);
if tab.is_fullscreen_active {
tabname.push_str(" (FULLSCREEN)");
} else if tab.is_sync_panes_active {
tabname.push_str(" (SYNC)");
}
if tab.has_bell_notification || tab.is_flashing_bell {
tabname.push_str(" [!]");
}
// we only color alternate tabs differently if we can't use the arrow fonts to separate them
if !capabilities.arrow_fonts {
is_alternate_tab = false;
}
render_tab(
tabname,
tab,
is_alternate_tab,
is_hovered,
palette,
separator,
)
}
pub(crate) fn get_tab_to_focus(
tab_line: &[LinePart],
active_tab_idx: usize,
mouse_click_col: usize,
) -> Option<usize> {
let clicked_line_part = get_clicked_line_part(tab_line, mouse_click_col)?;
let clicked_tab_idx = clicked_line_part.tab_index?;
// tabs are indexed starting from 1 so we need to add 1
let clicked_tab_idx = clicked_tab_idx + 1;
if clicked_tab_idx != active_tab_idx {
return Some(clicked_tab_idx);
}
None
}
pub(crate) fn get_clicked_line_part(
tab_line: &[LinePart],
mouse_click_col: usize,
) -> Option<&LinePart> {
let mut len = 0;
for tab_line_part in tab_line {
if mouse_click_col >= len && mouse_click_col < len + tab_line_part.len {
return Some(tab_line_part);
}
len += tab_line_part.len;
}
None
}
|