Skip to content

Commit

Permalink
feat(ui): swap layouts and stacked panes (#2167)
Browse files Browse the repository at this point in the history
* relayout working with hard coded layout

* work

* refactor(layout): PaneLayout => TiledPaneLayout

* tests passing

* tests passing

* tests passing

* stacked panes and passing tests

* tests for stacked panes

* refactor(panes): stacked panes

* fix: focusing into stacked panes from the left/right

* fix(layouts): handle stacked layouts in the middle of the screen

* fix(pane-stack): focus correctly when coming to stack from above/below

* fix(stacked-panes): resize stack

* fix(stacked-panes): focus with mouse

* fix(stacked-panes): focus next pane

* fix(layout-applier): sane focus order

* fix(stacked-panes): better titles for one-liners

* fix(stacked-panes): handle moving pane location in stack

* fix(relayout): properly calculate display area

* fix(relayout): properly calculate rounding errors

* fix(stacked-panes): properly handle closing a pane near a stack

* fix(swap-layouts): adjust swap layout sort order

* feat(swap-layouts): ui + ux

* fix(swap-layouts): include base layout

* refactor(layout): remove unused method

* fix(swap-layouts): respect pane contents and focus

* work

* fix(swap-layouts): load swap layouts from external file

* fix(swap-layouts): properly truncate layout children

* fix(stacked-panes): allow stacked panes to become fullscreen

* fix(swap-layouts): work with multiple tabs

* fix(swap-layouts): embed/eject panes properly with auto-layout

* fix(stacked-panes): close last pane in stack

* fix(stacked-panes): move focus for all clients in stack

* fix(floating-panes): set layout damaged when moving panes

* fix(relayout): move out of unfitting layout when resizing whole tab

* fix(ui): background color for swap layout indicator

* fix(keybinds): add switch next layout in tmux

* fix(ui): swap layout indication in compact layout

* fix(compact): correct swap constraint

* fix(tests): tmux swap config shortcut

* fix(resizes): cache resizes so as not to confuse panes (eg. vim) with multiple resizes that it debounces weirdly

* feat(cli): dump swap layouts

* fix(ui): stacked panes without pane frames

* fix(ux): move pane forward/backwards also with floating panes

* refactor(lint): remove unused stuff

* refactor(tab): move swap layouts to separate file

* style(fmt): rustfmt

* style(fmt): rustfmt

* refactor(panes): various cleanups

* chore(deps): upgrade termwiz to get alt left-bracket

* fix(assets): merge conflicts of binary files

* style(fmt): rustfmt

* style(clippy): no thank you!

* chore(repo): remove garbage file
  • Loading branch information
imsnif authored Feb 17, 2023
1 parent 1517036 commit f1ff272
Show file tree
Hide file tree
Showing 204 changed files with 16,276 additions and 2,902 deletions.
94 changes: 94 additions & 0 deletions default-plugins/compact-bar/src/line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ pub fn tab_line(
palette: Palette,
capabilities: PluginCapabilities,
mode: InputMode,
active_swap_layout_name: &Option<String>,
is_swap_layout_dirty: bool,
) -> Vec<LinePart> {
let mut tabs_after_active = all_tabs.split_off(active_tab_index);
let mut tabs_before_active = all_tabs;
Expand Down Expand Up @@ -283,5 +285,97 @@ pub fn tab_line(
capabilities,
);
prefix.append(&mut tabs_to_render);

let current_title_len = get_current_title_len(&prefix);
if current_title_len < cols {
let mut remaining_space = cols - current_title_len;
if let Some(swap_layout_status) = swap_layout_status(
remaining_space,
active_swap_layout_name,
is_swap_layout_dirty,
mode,
&palette,
tab_separator(capabilities),
) {
remaining_space -= swap_layout_status.len;
let mut buffer = String::new();
for _ in 0..remaining_space {
buffer.push_str(&style!(palette.black, palette.black).paint(" ").to_string());
}
prefix.push(LinePart {
part: buffer,
len: remaining_space,
tab_index: None,
});
prefix.push(swap_layout_status);
}
}

prefix
}

fn swap_layout_status(
max_len: usize,
swap_layout_name: &Option<String>,
is_swap_layout_damaged: bool,
input_mode: InputMode,
palette: &Palette,
separator: &str,
) -> Option<LinePart> {
match swap_layout_name {
Some(swap_layout_name) => {
let mut swap_layout_name = format!(" {} ", swap_layout_name);
swap_layout_name.make_ascii_uppercase();
let swap_layout_name_len = swap_layout_name.len() + 3;

let (prefix_separator, swap_layout_name, suffix_separator) =
if input_mode == InputMode::Locked {
(
style!(palette.black, palette.fg).paint(separator),
style!(palette.black, palette.fg)
.italic()
.paint(&swap_layout_name),
style!(palette.fg, palette.black).paint(separator),
)
} else if is_swap_layout_damaged {
(
style!(palette.black, palette.fg).paint(separator),
style!(palette.black, palette.fg)
.bold()
.paint(&swap_layout_name),
style!(palette.fg, palette.black).paint(separator),
)
} else {
(
style!(palette.black, palette.green).paint(separator),
style!(palette.black, palette.green)
.bold()
.paint(&swap_layout_name),
style!(palette.green, palette.black).paint(separator),
)
};
let swap_layout_indicator = format!(
"{}{}{}",
prefix_separator, swap_layout_name, suffix_separator
);
let (part, full_len) = (format!("{}", swap_layout_indicator), swap_layout_name_len);
let short_len = swap_layout_name_len + 1; // 1 is the space between
if full_len <= max_len {
Some(LinePart {
part,
len: full_len,
tab_index: None,
})
} else if short_len <= max_len && input_mode != InputMode::Locked {
Some(LinePart {
part: swap_layout_indicator,
len: short_len,
tab_index: None,
})
} else {
None
}
},
None => None,
}
}
6 changes: 6 additions & 0 deletions default-plugins/compact-bar/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ impl ZellijPlugin for State {
}
let mut all_tabs: Vec<LinePart> = vec![];
let mut active_tab_index = 0;
let mut active_swap_layout_name = None;
let mut is_swap_layout_dirty = false;
let mut is_alternate_tab = false;
for t in &mut self.tabs {
let mut tabname = t.name.clone();
Expand All @@ -102,6 +104,8 @@ impl ZellijPlugin for State {
active_tab_index = t.position;
} else if t.active {
active_tab_index = t.position;
is_swap_layout_dirty = t.is_swap_layout_dirty;
active_swap_layout_name = t.active_swap_layout_name.clone();
}
let tab = tab_style(
tabname,
Expand All @@ -121,6 +125,8 @@ impl ZellijPlugin for State {
self.mode_info.style.colors,
self.mode_info.capabilities,
self.mode_info.mode,
&active_swap_layout_name,
is_swap_layout_dirty,
);
let mut s = String::new();
let mut len_cnt = 0;
Expand Down
146 changes: 137 additions & 9 deletions default-plugins/status-bar/src/first_line.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use ansi_term::ANSIStrings;
use ansi_term::{unstyled_len, ANSIStrings};
use zellij_tile::prelude::actions::Action;
use zellij_tile::prelude::*;

use crate::color_elements;
use crate::{action_key, get_common_modifier, TO_NORMAL};
use crate::{
action_key, action_key_group, get_common_modifier, style_key_with_modifier, TO_NORMAL,
};
use crate::{ColoredElements, LinePart};

struct KeyShortcut {
Expand Down Expand Up @@ -232,6 +234,102 @@ fn key_indicators(
line_part
}

fn swap_layout_keycode(mode_info: &ModeInfo, palette: &Palette) -> LinePart {
let mode_keybinds = mode_info.get_mode_keybinds();
let prev_next_keys = action_key_group(
&mode_keybinds,
&[&[Action::PreviousSwapLayout], &[Action::NextSwapLayout]],
);
let prev_next_keys_indicator =
style_key_with_modifier(&prev_next_keys, palette, Some(palette.black));
let keycode = ANSIStrings(&prev_next_keys_indicator);
let len = unstyled_len(&keycode);
let part = keycode.to_string();
LinePart { part, len }
}

fn swap_layout_status(
max_len: usize,
swap_layout_name: &Option<String>,
is_swap_layout_damaged: bool,
mode_info: &ModeInfo,
colored_elements: ColoredElements,
palette: &Palette,
separator: &str,
) -> Option<LinePart> {
match swap_layout_name {
Some(swap_layout_name) => {
let mut swap_layout_name = format!(" {} ", swap_layout_name);
swap_layout_name.make_ascii_uppercase();
let keycode = swap_layout_keycode(mode_info, palette);
let swap_layout_name_len = swap_layout_name.len() + 3; // 2 for the arrow separators, one for the screen end buffer
//
macro_rules! style_swap_layout_indicator {
($style_name:ident) => {{
(
colored_elements
.$style_name
.prefix_separator
.paint(separator),
colored_elements
.$style_name
.styled_text
.paint(&swap_layout_name),
colored_elements
.$style_name
.suffix_separator
.paint(separator),
)
}};
}
let (prefix_separator, swap_layout_name, suffix_separator) =
if mode_info.mode == InputMode::Locked {
style_swap_layout_indicator!(disabled)
} else if is_swap_layout_damaged {
style_swap_layout_indicator!(unselected)
} else {
style_swap_layout_indicator!(selected)
};
let swap_layout_indicator = format!(
"{}{}{}",
prefix_separator, swap_layout_name, suffix_separator
);
let (part, full_len) = if mode_info.mode == InputMode::Locked {
(
format!("{}", swap_layout_indicator),
swap_layout_name_len, // 1 is the space between
)
} else {
(
format!(
"{}{}{}{}",
keycode,
colored_elements.superkey_prefix.paint(" "),
swap_layout_indicator,
colored_elements.superkey_prefix.paint(" ")
),
keycode.len + swap_layout_name_len + 1, // 1 is the space between
)
};
let short_len = swap_layout_name_len + 1; // 1 is the space between
if full_len <= max_len {
Some(LinePart {
part,
len: full_len,
})
} else if short_len <= max_len && mode_info.mode != InputMode::Locked {
Some(LinePart {
part: swap_layout_indicator,
len: short_len,
})
} else {
None
}
},
None => None,
}
}

/// Get the keybindings for switching `InputMode`s and `Quit` visible in status bar.
///
/// Return a Vector of `Key`s where each `Key` is a shortcut to switch to some `InputMode` or Quit
Expand Down Expand Up @@ -351,7 +449,12 @@ fn get_key_shortcut_for_mode<'a>(
None
}

pub fn first_line(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart {
pub fn first_line(
help: &ModeInfo,
tab_info: Option<&TabInfo>,
max_len: usize,
separator: &str,
) -> LinePart {
let supports_arrow_fonts = !help.capabilities.arrow_fonts;
let colored_elements = color_elements(help.style.colors, !supports_arrow_fonts);
let binds = &help.get_mode_keybinds();
Expand Down Expand Up @@ -432,7 +535,32 @@ pub fn first_line(help: &ModeInfo, max_len: usize, separator: &str) -> LinePart
));
}

key_indicators(max_len, &default_keys, colored_elements, separator, help)
let mut key_indicators =
key_indicators(max_len, &default_keys, colored_elements, separator, help);
if key_indicators.len < max_len {
if let Some(tab_info) = tab_info {
let mut remaining_space = max_len - key_indicators.len;
if let Some(swap_layout_status) = swap_layout_status(
remaining_space,
&tab_info.active_swap_layout_name,
tab_info.is_swap_layout_dirty,
help,
colored_elements,
&help.style.colors,
separator,
) {
remaining_space -= swap_layout_status.len;
for _ in 0..remaining_space {
key_indicators.part.push_str(
&ANSIStrings(&[colored_elements.superkey_prefix.paint(" ")]).to_string(),
);
key_indicators.len += 1;
}
key_indicators.append(&swap_layout_status);
}
}
}
key_indicators
}

#[cfg(test)]
Expand Down Expand Up @@ -735,7 +863,7 @@ mod tests {
..ModeInfo::default()
};

let ret = first_line(&mode_info, 500, ">");
let ret = first_line(&mode_info, None, 500, ">");
let ret = unstyle(ret);

assert_eq!(
Expand All @@ -759,7 +887,7 @@ mod tests {
..ModeInfo::default()
};

let ret = first_line(&mode_info, 500, ">");
let ret = first_line(&mode_info, None, 500, ">");
let ret = unstyle(ret);

assert_eq!(
Expand All @@ -785,7 +913,7 @@ mod tests {
..ModeInfo::default()
};

let ret = first_line(&mode_info, 500, ">");
let ret = first_line(&mode_info, None, 500, ">");
let ret = unstyle(ret);

assert_eq!(
Expand All @@ -812,7 +940,7 @@ mod tests {
..ModeInfo::default()
};

let ret = first_line(&mode_info, 50, ">");
let ret = first_line(&mode_info, None, 50, ">");
let ret = unstyle(ret);

assert_eq!(ret, " Ctrl + >> a >> b >> c >> d >> e >".to_string());
Expand All @@ -833,7 +961,7 @@ mod tests {
..ModeInfo::default()
};

let ret = first_line(&mode_info, 30, "");
let ret = first_line(&mode_info, None, 30, "");
let ret = unstyle(ret);

assert_eq!(ret, " Ctrl + a b c ".to_string());
Expand Down
Loading

0 comments on commit f1ff272

Please sign in to comment.