Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(plugins): session manager cwd and new filepicker #3200

Merged
merged 11 commits into from
Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions default-plugins/fixture-plugin-for-tests/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ impl ZellijPlugin for State {
EventType::FileSystemUpdate,
EventType::FileSystemDelete,
]);
watch_filesystem();
}

fn update(&mut self, event: Event) -> bool {
Expand Down
1 change: 1 addition & 0 deletions default-plugins/session-manager/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ chrono = "0.4.0"
fuzzy-matcher = "0.3.7"
unicode-width = "0.1.10"
humantime = "2.1.0"
uuid = { version = "1.7.0", features = ["v4"] }
56 changes: 50 additions & 6 deletions default-plugins/session-manager/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ mod new_session_info;
mod resurrectable_sessions;
mod session_list;
mod ui;
use zellij_tile::prelude::*;

use std::collections::BTreeMap;
use uuid::Uuid;
use zellij_tile::prelude::*;

use new_session_info::NewSessionInfo;
use ui::{
Expand Down Expand Up @@ -45,6 +45,7 @@ struct State {
colors: Colors,
is_welcome_screen: bool,
show_kill_all_sessions_warning: bool,
request_ids: Vec<String>,
}

register_plugin!(State);
Expand All @@ -66,6 +67,28 @@ impl ZellijPlugin for State {
]);
}

fn pipe(&mut self, pipe_message: PipeMessage) -> bool {
if pipe_message.name == "filepicker_result" {
match (pipe_message.payload, pipe_message.args.get("request_id")) {
(Some(payload), Some(request_id)) => {
match self.request_ids.iter().position(|p| p == request_id) {
Some(request_id_position) => {
self.request_ids.remove(request_id_position);
let new_session_folder = std::path::PathBuf::from(payload);
self.new_session_info.new_session_folder = Some(new_session_folder);
},
None => {
eprintln!("request id not found");
},
}
},
_ => {},
}
true
} else {
false
}
}
fn update(&mut self, event: Event) -> bool {
let mut should_render = false;
match event {
Expand Down Expand Up @@ -109,7 +132,7 @@ impl ZellijPlugin for State {
render_new_session_block(
&self.new_session_info,
self.colors,
height,
height.saturating_sub(2),
width,
x,
y + 2,
Expand Down Expand Up @@ -184,12 +207,33 @@ impl State {
} else if let Key::Ctrl('w') = key {
self.active_screen = ActiveScreen::NewSession;
should_render = true;
} else if let Key::Ctrl('c') = key {
self.new_session_info.handle_key(key);
should_render = true;
} else if let Key::BackTab = key {
self.toggle_active_screen();
should_render = true;
} else if let Key::Ctrl('f') = key {
let request_id = Uuid::new_v4();
let mut config = BTreeMap::new();
let mut args = BTreeMap::new();
self.request_ids.push(request_id.to_string());
// we insert this into the config so that a new plugin will be opened (the plugin's
// uniqueness is determined by its name/url as well as its config)
config.insert("request_id".to_owned(), request_id.to_string());
// we also insert this into the args so that the plugin will have an easier access to
// it
args.insert("request_id".to_owned(), request_id.to_string());
pipe_message_to_plugin(
MessageToPlugin::new("filepicker")
.with_plugin_url("filepicker")
.with_plugin_config(config)
.new_plugin_instance_should_have_pane_title(
"Select folder for the new session...",
)
.with_args(args),
);
should_render = true;
} else if let Key::Ctrl('c') = key {
self.new_session_info.new_session_folder = None;
should_render = true;
} else if let Key::Esc = key {
self.new_session_info.handle_key(key);
should_render = true;
Expand Down
5 changes: 4 additions & 1 deletion default-plugins/session-manager/src/new_session_info.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use fuzzy_matcher::skim::SkimMatcherV2;
use fuzzy_matcher::FuzzyMatcher;
use std::cmp::Ordering;
use std::path::PathBuf;
use zellij_tile::prelude::*;

#[derive(Default)]
pub struct NewSessionInfo {
name: String,
layout_list: LayoutList,
entering_new_session_info: EnteringState,
pub new_session_folder: Option<PathBuf>,
}

#[derive(Eq, PartialEq)]
Expand Down Expand Up @@ -104,7 +106,8 @@ impl NewSessionInfo {
if new_session_name != current_session_name.as_ref().map(|s| s.as_str()) {
match new_session_layout {
Some(new_session_layout) => {
switch_session_with_layout(new_session_name, new_session_layout, None)
let cwd = self.new_session_folder.as_ref().map(|c| PathBuf::from(c));
switch_session_with_layout(new_session_name, new_session_layout, cwd)
},
None => {
switch_session(new_session_name);
Expand Down
178 changes: 169 additions & 9 deletions default-plugins/session-manager/src/ui/components.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::path::PathBuf;
use unicode_width::UnicodeWidthChar;
use unicode_width::UnicodeWidthStr;
use zellij_tile::prelude::*;
Expand Down Expand Up @@ -519,9 +520,6 @@ pub fn render_screen_toggle(active_screen: ActiveScreen, x: usize, y: usize, max
let key_indication_len = key_indication_text.chars().count() + 1;
let first_ribbon_length = new_session_text.chars().count() + 4;
let second_ribbon_length = running_sessions_text.chars().count() + 4;
let third_ribbon_length = exited_sessions_text.chars().count() + 4;
let total_len =
key_indication_len + first_ribbon_length + second_ribbon_length + third_ribbon_length;
let key_indication_x = x;
let first_ribbon_x = key_indication_x + key_indication_len;
let second_ribbon_x = first_ribbon_x + first_ribbon_length;
Expand Down Expand Up @@ -552,6 +550,140 @@ pub fn render_screen_toggle(active_screen: ActiveScreen, x: usize, y: usize, max
print_ribbon_with_coordinates(exited_sessions_text, third_ribbon_x, y, None, None);
}

fn render_new_session_folder_prompt(
new_session_info: &NewSessionInfo,
colors: Colors,
x: usize,
y: usize,
max_cols: usize,
) {
match new_session_info.new_session_folder.as_ref() {
Some(new_session_folder) => {
let folder_prompt = "New session folder:";
let short_folder_prompt = "Folder:";
let new_session_path = new_session_folder.clone();
let new_session_folder = new_session_folder.display().to_string();
let change_folder_shortcut_text = "<Ctrl f>";
let change_folder_shortcut = colors.magenta(&change_folder_shortcut_text);
let to_change = "to change";
let reset_folder_shortcut_text = "<Ctrl c>";
let reset_folder_shortcut = colors.magenta(reset_folder_shortcut_text);
let to_reset = "to reset";
if max_cols
>= folder_prompt.width()
+ new_session_folder.width()
+ change_folder_shortcut_text.width()
+ to_change.width()
+ reset_folder_shortcut_text.width()
+ to_reset.width()
+ 8
{
print!(
"\u{1b}[m{}{} {} ({} {}, {} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(folder_prompt),
colors.orange(&new_session_folder),
change_folder_shortcut,
to_change,
reset_folder_shortcut,
to_reset,
);
} else if max_cols
>= short_folder_prompt.width()
+ new_session_folder.width()
+ change_folder_shortcut_text.width()
+ to_change.width()
+ reset_folder_shortcut_text.width()
+ to_reset.width()
+ 8
{
print!(
"\u{1b}[m{}{} {} ({} {}, {} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt),
colors.orange(&new_session_folder),
change_folder_shortcut,
to_change,
reset_folder_shortcut,
to_reset,
);
} else if max_cols
>= short_folder_prompt.width()
+ new_session_folder.width()
+ change_folder_shortcut_text.width()
+ reset_folder_shortcut_text.width()
+ 5
{
print!(
"\u{1b}[m{}{} {} ({}/{})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt),
colors.orange(&new_session_folder),
change_folder_shortcut,
reset_folder_shortcut,
);
} else {
let total_len = short_folder_prompt.width()
+ change_folder_shortcut_text.width()
+ reset_folder_shortcut_text.width()
+ 5;
let max_path_len = max_cols.saturating_sub(total_len);
let truncated_path = truncate_path(
new_session_path,
new_session_folder.width().saturating_sub(max_path_len),
);
print!(
"\u{1b}[m{}{} {} ({}/{})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt),
colors.orange(&truncated_path),
change_folder_shortcut,
reset_folder_shortcut,
);
}
},
None => {
let folder_prompt = "New session folder:";
let short_folder_prompt = "Folder:";
let change_folder_shortcut_text = "<Ctrl f>";
let change_folder_shortcut = colors.magenta(change_folder_shortcut_text);
let to_set = "to set";

if max_cols
>= folder_prompt.width() + change_folder_shortcut_text.width() + to_set.width() + 4
{
print!(
"\u{1b}[m{}{} ({} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(folder_prompt),
change_folder_shortcut,
to_set,
);
} else if max_cols
>= short_folder_prompt.width()
+ change_folder_shortcut_text.width()
+ to_set.width()
+ 4
{
print!(
"\u{1b}[m{}{} ({} {})",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt),
change_folder_shortcut,
to_set,
);
} else {
print!(
"\u{1b}[m{}{} {}",
format!("\u{1b}[{};{}H", y + 1, x + 1),
colors.green(short_folder_prompt),
change_folder_shortcut,
);
}
},
}
}

pub fn render_new_session_block(
new_session_info: &NewSessionInfo,
colors: Colors,
Expand Down Expand Up @@ -615,6 +747,7 @@ pub fn render_new_session_block(
}
render_layout_selection_list(
new_session_info,
colors,
max_rows_of_new_session_block.saturating_sub(1),
max_cols_of_new_session_block,
x,
Expand All @@ -625,6 +758,7 @@ pub fn render_new_session_block(

pub fn render_layout_selection_list(
new_session_info: &NewSessionInfo,
colors: Colors,
max_rows_of_new_session_block: usize,
max_cols_of_new_session_block: usize,
x: usize,
Expand Down Expand Up @@ -658,7 +792,7 @@ pub fn render_layout_selection_list(
let layout_name = layout_info.name();
let layout_name_len = layout_name.width();
let is_builtin = layout_info.is_builtin();
if i > max_rows_of_new_session_block {
if i > max_rows_of_new_session_block.saturating_sub(1) {
break;
} else {
let mut layout_cell = if is_builtin {
Expand All @@ -682,7 +816,15 @@ pub fn render_layout_selection_list(
table = table.add_styled_row(vec![arrow_cell, layout_cell]);
}
}
print_table_with_coordinates(table, x, y + 3, None, None);
let table_y = y + 3;
print_table_with_coordinates(table, x, table_y, None, None);
render_new_session_folder_prompt(
new_session_info,
colors,
x,
(y + max_rows_of_new_session_block).saturating_sub(3),
max_cols_of_new_session_block,
);
}

pub fn render_error(error_text: &str, rows: usize, columns: usize, x: usize, y: usize) {
Expand Down Expand Up @@ -733,10 +875,6 @@ pub fn render_controls_line(
}
},
ActiveScreen::AttachToSession => {
let arrows = colors.magenta("<←↓↑→>");
let navigate = colors.bold("Navigate");
let enter = colors.magenta("<ENTER>");
let select = colors.bold("Attach");
let rename = colors.magenta("<Ctrl r>");
let rename_text = colors.bold("Rename");
let disconnect = colors.magenta("<Ctrl x>");
Expand Down Expand Up @@ -817,3 +955,25 @@ impl Colors {
self.color(&self.palette.magenta, text)
}
}

fn truncate_path(path: PathBuf, mut char_count_to_remove: usize) -> String {
let mut truncated = String::new();
let component_count = path.iter().count();
for (i, component) in path.iter().enumerate() {
let mut component_str = component.to_string_lossy().to_string();
if char_count_to_remove > 0 {
truncated.push(component_str.remove(0));
if i != 0 && i + 1 != component_count {
truncated.push('/');
}
char_count_to_remove =
char_count_to_remove.saturating_sub(component_str.width().saturating_sub(1));
} else {
truncated.push_str(&component_str);
if i != 0 && i + 1 != component_count {
truncated.push('/');
}
}
}
truncated
}
2 changes: 1 addition & 1 deletion default-plugins/strider/.cargo/config.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[build]
target = "wasm32-wasi"
target = "wasm32-wasi"
Loading
Loading