summaryrefslogtreecommitdiffstats
path: root/default-plugins
diff options
context:
space:
mode:
authorPaulo Coelho <9609090+prscoelho@users.noreply.github.com>2021-09-09 15:38:10 +0100
committerGitHub <noreply@github.com>2021-09-09 16:38:10 +0200
commitf2850d2931dddbc3d3ac4f4ac3c656df63bc1ebb (patch)
tree271e345fa5651da2461cc6ec3756a1dce6f9d356 /default-plugins
parentf0da6872df49815de723b11fe9cf151be0de4e61 (diff)
fix(tab-bar): prevent active tab from being hidden (#703)
Diffstat (limited to 'default-plugins')
-rw-r--r--default-plugins/tab-bar/src/line.rs172
-rw-r--r--default-plugins/tab-bar/src/main.rs2
-rw-r--r--default-plugins/tab-bar/src/tab.rs4
3 files changed, 82 insertions, 96 deletions
diff --git a/default-plugins/tab-bar/src/line.rs b/default-plugins/tab-bar/src/line.rs
index 4cdc02c44..be5623ff9 100644
--- a/default-plugins/tab-bar/src/line.rs
+++ b/default-plugins/tab-bar/src/line.rs
@@ -8,39 +8,82 @@ fn get_current_title_len(current_title: &[LinePart]) -> usize {
current_title.iter().map(|p| p.len).sum()
}
+// move elements from before_active and after_active into tabs_to_render while they fit in cols
+// adds collapsed_tabs to the left and right if there's left over tabs that don't fit
fn populate_tabs_in_tab_line(
tabs_before_active: &mut Vec<LinePart>,
tabs_after_active: &mut Vec<LinePart>,
tabs_to_render: &mut Vec<LinePart>,
cols: usize,
+ palette: Palette,
+ capabilities: PluginCapabilities,
) {
- let mut take_next_tab_from_tabs_after = true;
+ let mut middle_size = get_current_title_len(tabs_to_render);
+
+ let mut total_left = 0;
+ let mut total_right = 0;
loop {
- if tabs_before_active.is_empty() && tabs_after_active.is_empty() {
- break;
- }
- let current_title_len = get_current_title_len(tabs_to_render);
- if current_title_len >= cols {
+ let left_count = tabs_before_active.len();
+ let right_count = tabs_after_active.len();
+ let collapsed_left = left_more_message(left_count, palette, tab_separator(capabilities));
+ let collapsed_right = right_more_message(right_count, palette, tab_separator(capabilities));
+
+ let total_size = collapsed_left.len + middle_size + collapsed_right.len;
+
+ if total_size > cols {
+ // break and dont add collapsed tabs to tabs_to_render, they will not fit
break;
}
- let should_take_next_tab = take_next_tab_from_tabs_after;
- let can_take_next_tab = !tabs_after_active.is_empty()
- && tabs_after_active.get(0).unwrap().len + current_title_len <= cols;
- let can_take_previous_tab = !tabs_before_active.is_empty()
- && tabs_before_active.last().unwrap().len + current_title_len <= cols;
- if should_take_next_tab && can_take_next_tab {
- let next_tab = tabs_after_active.remove(0);
- tabs_to_render.push(next_tab);
- take_next_tab_from_tabs_after = false;
- } else if can_take_previous_tab {
- let previous_tab = tabs_before_active.pop().unwrap();
- tabs_to_render.insert(0, previous_tab);
- take_next_tab_from_tabs_after = true;
- } else if can_take_next_tab {
- let next_tab = tabs_after_active.remove(0);
- tabs_to_render.push(next_tab);
- take_next_tab_from_tabs_after = false;
+
+ let left = if let Some(tab) = tabs_before_active.last() {
+ tab.len
+ } else {
+ usize::MAX
+ };
+
+ let right = if let Some(tab) = tabs_after_active.first() {
+ tab.len
} else {
+ usize::MAX
+ };
+
+ // total size is shortened if the next tab to be added is the last one, as that will remove the collapsed tab
+ let size_by_adding_left =
+ left.saturating_add(total_size)
+ .saturating_sub(if left_count == 1 {
+ collapsed_left.len
+ } else {
+ 0
+ });
+ let size_by_adding_right =
+ right
+ .saturating_add(total_size)
+ .saturating_sub(if right_count == 1 {
+ collapsed_right.len
+ } else {
+ 0
+ });
+
+ let left_fits = size_by_adding_left <= cols;
+ let right_fits = size_by_adding_right <= cols;
+ // active tab is kept in the middle by adding to the side that
+ // has less width, or if the tab on the other side doesn' fit
+ if (total_left <= total_right || !right_fits) && left_fits {
+ // add left tab
+ let tab = tabs_before_active.pop().unwrap();
+ middle_size += tab.len;
+ total_left += tab.len;
+ tabs_to_render.insert(0, tab);
+ } else if right_fits {
+ // add right tab
+ let tab = tabs_after_active.remove(0);
+ middle_size += tab.len;
+ total_right += tab.len;
+ tabs_to_render.push(tab);
+ } else {
+ // there's either no space to add more tabs or no more tabs to add, so we're done
+ tabs_to_render.insert(0, collapsed_left);
+ tabs_to_render.push(collapsed_right);
break;
}
}
@@ -56,7 +99,8 @@ fn left_more_message(tab_count_to_the_left: usize, palette: Palette, separator:
" ← +many ".to_string()
};
// 238
- let more_text_len = more_text.chars().count() + 2; // 2 for the arrows
+ // chars length plus separator length on both sides
+ let more_text_len = more_text.chars().count() + 2 * separator.chars().count();
let left_separator = style!(palette.cyan, palette.orange).paint(separator);
let more_styled_text = style!(palette.black, palette.orange)
.bold()
@@ -85,7 +129,8 @@ fn right_more_message(
} else {
" +many → ".to_string()
};
- let more_text_len = more_text.chars().count() + 1; // 2 for the arrow
+ // chars length plus separator length on both sides
+ let more_text_len = more_text.chars().count() + 2 * separator.chars().count();
let left_separator = style!(palette.cyan, palette.orange).paint(separator);
let more_styled_text = style!(palette.black, palette.orange)
.bold()
@@ -101,48 +146,6 @@ fn right_more_message(
}
}
-fn add_previous_tabs_msg(
- tabs_before_active: &mut Vec<LinePart>,
- tabs_to_render: &mut Vec<LinePart>,
- title_bar: &mut Vec<LinePart>,
- cols: usize,
- palette: Palette,
- separator: &str,
-) {
- while get_current_title_len(tabs_to_render)
- + left_more_message(tabs_before_active.len(), palette, separator).len
- >= cols
- && !tabs_to_render.is_empty()
- {
- tabs_before_active.push(tabs_to_render.remove(0));
- }
-
- let left_more_message = left_more_message(tabs_before_active.len(), palette, separator);
- if left_more_message.len <= cols {
- title_bar.push(left_more_message);
- }
-}
-
-fn add_next_tabs_msg(
- tabs_after_active: &mut Vec<LinePart>,
- title_bar: &mut Vec<LinePart>,
- cols: usize,
- palette: Palette,
- separator: &str,
-) {
- while get_current_title_len(title_bar)
- + right_more_message(tabs_after_active.len(), palette, separator).len
- >= cols
- && !title_bar.is_empty()
- {
- tabs_after_active.insert(0, title_bar.pop().unwrap());
- }
- let right_more_message = right_more_message(tabs_after_active.len(), palette, separator);
- if right_more_message.len < cols {
- title_bar.push(right_more_message);
- }
-}
-
fn tab_line_prefix(session_name: Option<&str>, palette: Palette, cols: usize) -> Vec<LinePart> {
let prefix_text = " Zellij ".to_string();
@@ -184,7 +187,6 @@ pub fn tab_line(
palette: Palette,
capabilities: PluginCapabilities,
) -> Vec<LinePart> {
- let mut tabs_to_render = Vec::new();
let mut tabs_after_active = all_tabs.split_off(active_tab_index);
let mut tabs_before_active = all_tabs;
let active_tab = if !tabs_after_active.is_empty() {
@@ -194,38 +196,22 @@ pub fn tab_line(
};
let mut prefix = tab_line_prefix(session_name, palette, cols);
let prefix_len = get_current_title_len(&prefix);
- if prefix_len + active_tab.len <= cols {
- tabs_to_render.push(active_tab);
+
+ // if active tab alone won't fit in cols, don't draw any tabs
+ if prefix_len + active_tab.len > cols {
+ return prefix;
}
+ let mut tabs_to_render = vec![active_tab];
+
populate_tabs_in_tab_line(
&mut tabs_before_active,
&mut tabs_after_active,
&mut tabs_to_render,
cols.saturating_sub(prefix_len),
+ palette,
+ capabilities,
);
-
- let mut tab_line: Vec<LinePart> = vec![];
- if !tabs_before_active.is_empty() {
- add_previous_tabs_msg(
- &mut tabs_before_active,
- &mut tabs_to_render,
- &mut tab_line,
- cols.saturating_sub(prefix_len),
- palette,
- tab_separator(capabilities),
- );
- }
- tab_line.append(&mut tabs_to_render);
- if !tabs_after_active.is_empty() {
- add_next_tabs_msg(
- &mut tabs_after_active,
- &mut tab_line,
- cols.saturating_sub(prefix_len),
- palette,
- tab_separator(capabilities),
- );
- }
- prefix.append(&mut tab_line);
+ prefix.append(&mut tabs_to_render);
prefix
}
diff --git a/default-plugins/tab-bar/src/main.rs b/default-plugins/tab-bar/src/main.rs
index d4111cfae..850781261 100644
--- a/default-plugins/tab-bar/src/main.rs
+++ b/default-plugins/tab-bar/src/main.rs
@@ -65,7 +65,7 @@ impl ZellijPlugin for State {
self.mode_info.session_name.as_deref(),
all_tabs,
active_tab_index,
- cols,
+ cols.saturating_sub(1),
self.mode_info.palette,
self.mode_info.capabilities,
);
diff --git a/default-plugins/tab-bar/src/tab.rs b/default-plugins/tab-bar/src/tab.rs
index 9edfba13f..dfa5ab776 100644
--- a/default-plugins/tab-bar/src/tab.rs
+++ b/default-plugins/tab-bar/src/tab.rs
@@ -5,7 +5,7 @@ use zellij_tile_utils::style;
pub fn active_tab(text: String, palette: Palette, separator: &str) -> LinePart {
let left_separator = style!(palette.cyan, palette.green).paint(separator);
- let tab_text_len = text.chars().count() + 4; // 2 for left and right separators, 2 for the text padding
+ let tab_text_len = text.chars().count() + 2 + separator.chars().count() * 2; // 2 for left and right separators, 2 for the text padding
let tab_styled_text = style!(palette.black, palette.green)
.bold()
.paint(format!(" {} ", text));
@@ -22,7 +22,7 @@ pub fn active_tab(text: String, palette: Palette, separator: &str) -> LinePart {
pub fn non_active_tab(text: String, palette: Palette, separator: &str) -> LinePart {
let left_separator = style!(palette.cyan, palette.fg).paint(separator);
- let tab_text_len = text.chars().count() + 4; // 2 for left and right separators, 2 for the padding
+ let tab_text_len = text.chars().count() + 2 + separator.chars().count() * 2; // 2 for left and right separators, 2 for the text padding
let tab_styled_text = style!(palette.black, palette.fg)
.bold()
.paint(format!(" {} ", text));