feat(ux): first run setup-wizard (#3556)
* separate saved/runtime structure, kind of working * serializing config * work * work * save config through the configuration screen * work * startup wizard * style(code): cleanups * fix(session): reload config from disk when switching sessions * style(fmt): rustfmt * fix(config): propagate cli config options to screen * style(fmt): rustfmt
This commit is contained in:
parent
c25166c30a
commit
056537d3ee
53 changed files with 4985 additions and 314 deletions
|
|
@ -2,6 +2,8 @@ use zellij_tile::prelude::*;
|
||||||
|
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
|
||||||
|
static UI_SIZE: usize = 15;
|
||||||
|
|
||||||
struct State {
|
struct State {
|
||||||
userspace_configuration: BTreeMap<String, String>,
|
userspace_configuration: BTreeMap<String, String>,
|
||||||
selected_index: Option<usize>,
|
selected_index: Option<usize>,
|
||||||
|
|
@ -16,6 +18,9 @@ struct State {
|
||||||
preset_color_index: usize,
|
preset_color_index: usize,
|
||||||
primary_leader_key_color_index: usize,
|
primary_leader_key_color_index: usize,
|
||||||
secondary_leader_key_color_index: usize,
|
secondary_leader_key_color_index: usize,
|
||||||
|
notification: Option<String>,
|
||||||
|
is_setup_wizard: bool,
|
||||||
|
ui_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for State {
|
impl Default for State {
|
||||||
|
|
@ -43,6 +48,9 @@ impl Default for State {
|
||||||
secondary_leader_key_color_index: 0,
|
secondary_leader_key_color_index: 0,
|
||||||
mode_color_index: 2,
|
mode_color_index: 2,
|
||||||
preset_color_index: 1,
|
preset_color_index: 1,
|
||||||
|
notification: None,
|
||||||
|
is_setup_wizard: false,
|
||||||
|
ui_size: UI_SIZE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -51,6 +59,10 @@ register_plugin!(State);
|
||||||
|
|
||||||
impl ZellijPlugin for State {
|
impl ZellijPlugin for State {
|
||||||
fn load(&mut self, configuration: BTreeMap<String, String>) {
|
fn load(&mut self, configuration: BTreeMap<String, String>) {
|
||||||
|
self.is_setup_wizard = configuration
|
||||||
|
.get("is_setup_wizard")
|
||||||
|
.map(|v| v == "true")
|
||||||
|
.unwrap_or(false);
|
||||||
self.userspace_configuration = configuration;
|
self.userspace_configuration = configuration;
|
||||||
// we need the ReadApplicationState permission to receive the ModeUpdate and TabUpdate
|
// we need the ReadApplicationState permission to receive the ModeUpdate and TabUpdate
|
||||||
// events
|
// events
|
||||||
|
|
@ -64,12 +76,19 @@ impl ZellijPlugin for State {
|
||||||
PermissionType::ChangeApplicationState,
|
PermissionType::ChangeApplicationState,
|
||||||
]);
|
]);
|
||||||
subscribe(&[
|
subscribe(&[
|
||||||
EventType::ModeUpdate,
|
|
||||||
EventType::TabUpdate,
|
|
||||||
EventType::Key,
|
|
||||||
EventType::Timer,
|
|
||||||
EventType::PermissionRequestResult,
|
EventType::PermissionRequestResult,
|
||||||
|
EventType::Key,
|
||||||
|
EventType::FailedToWriteConfigToDisk,
|
||||||
]);
|
]);
|
||||||
|
if self.is_setup_wizard {
|
||||||
|
self.ui_size = 18;
|
||||||
|
self.selected_index = Some(0);
|
||||||
|
let own_plugin_id = get_plugin_ids().plugin_id;
|
||||||
|
rename_plugin_pane(own_plugin_id, "First Run Setup Wizard (Step 1/1)");
|
||||||
|
resize_focused_pane(Resize::Increase);
|
||||||
|
resize_focused_pane(Resize::Increase);
|
||||||
|
resize_focused_pane(Resize::Increase);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fn update(&mut self, event: Event) -> bool {
|
fn update(&mut self, event: Event) -> bool {
|
||||||
let mut should_render = false;
|
let mut should_render = false;
|
||||||
|
|
@ -80,10 +99,26 @@ impl ZellijPlugin for State {
|
||||||
Event::Key(key) => {
|
Event::Key(key) => {
|
||||||
if self.remapping_leaders {
|
if self.remapping_leaders {
|
||||||
should_render = self.handle_remapping_screen_key(key);
|
should_render = self.handle_remapping_screen_key(key);
|
||||||
|
} else if self.is_setup_wizard {
|
||||||
|
should_render = self.handle_setup_wizard_key(key);
|
||||||
} else {
|
} else {
|
||||||
should_render = self.handle_main_screen_key(key);
|
should_render = self.handle_main_screen_key(key);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Event::FailedToWriteConfigToDisk(config_file_path) => {
|
||||||
|
match config_file_path {
|
||||||
|
Some(failed_path) => {
|
||||||
|
self.notification = Some(format!(
|
||||||
|
"Failed to write configuration file: {}",
|
||||||
|
failed_path
|
||||||
|
));
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
self.notification = Some(format!("Failed to write configuration file."));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
should_render = true;
|
||||||
|
},
|
||||||
_ => (),
|
_ => (),
|
||||||
};
|
};
|
||||||
should_render
|
should_render
|
||||||
|
|
@ -91,6 +126,8 @@ impl ZellijPlugin for State {
|
||||||
fn render(&mut self, rows: usize, cols: usize) {
|
fn render(&mut self, rows: usize, cols: usize) {
|
||||||
if self.remapping_leaders {
|
if self.remapping_leaders {
|
||||||
self.render_remapping_leaders_screen(rows, cols);
|
self.render_remapping_leaders_screen(rows, cols);
|
||||||
|
} else if self.is_setup_wizard {
|
||||||
|
self.render_setup_wizard_screen(rows, cols);
|
||||||
} else {
|
} else {
|
||||||
self.render_main_screen(rows, cols);
|
self.render_main_screen(rows, cols);
|
||||||
}
|
}
|
||||||
|
|
@ -185,7 +222,10 @@ impl State {
|
||||||
}
|
}
|
||||||
fn handle_main_screen_key(&mut self, key: KeyWithModifier) -> bool {
|
fn handle_main_screen_key(&mut self, key: KeyWithModifier) -> bool {
|
||||||
let mut should_render = false;
|
let mut should_render = false;
|
||||||
if key.bare_key == BareKey::Down && key.has_no_modifiers() {
|
if self.notification.is_some() {
|
||||||
|
self.notification = None;
|
||||||
|
should_render = true;
|
||||||
|
} else if key.bare_key == BareKey::Down && key.has_no_modifiers() {
|
||||||
if self.selected_index.is_none() {
|
if self.selected_index.is_none() {
|
||||||
self.selected_index = Some(0);
|
self.selected_index = Some(0);
|
||||||
} else if self.selected_index < Some(1) {
|
} else if self.selected_index < Some(1) {
|
||||||
|
|
@ -205,45 +245,70 @@ impl State {
|
||||||
should_render = true;
|
should_render = true;
|
||||||
} else if key.bare_key == BareKey::Enter && key.has_no_modifiers() {
|
} else if key.bare_key == BareKey::Enter && key.has_no_modifiers() {
|
||||||
if let Some(selected) = self.selected_index.take() {
|
if let Some(selected) = self.selected_index.take() {
|
||||||
if selected == 0 {
|
let write_to_disk = false;
|
||||||
// TODO: these should be part of a "transaction" when they are
|
self.reconfigure(selected, write_to_disk);
|
||||||
// implemented
|
self.notification = Some("Configuration applied to current session.".to_owned());
|
||||||
reconfigure(default_keybinds(
|
should_render = true;
|
||||||
self.primary_modifier
|
} else {
|
||||||
.iter()
|
self.selected_index = Some(0);
|
||||||
.map(|m| m.to_string())
|
should_render = true;
|
||||||
.collect::<Vec<_>>()
|
}
|
||||||
.join(" "),
|
} else if key.bare_key == BareKey::Char(' ') && key.has_no_modifiers() {
|
||||||
self.secondary_modifier
|
if let Some(selected) = self.selected_index.take() {
|
||||||
.iter()
|
let write_to_disk = true;
|
||||||
.map(|m| m.to_string())
|
self.reconfigure(selected, write_to_disk);
|
||||||
.collect::<Vec<_>>()
|
self.notification = Some("Configuration applied and saved to disk.".to_owned());
|
||||||
.join(" "),
|
|
||||||
));
|
|
||||||
switch_to_input_mode(&InputMode::Normal);
|
|
||||||
} else if selected == 1 {
|
|
||||||
// TODO: these should be part of a "transaction" when they are
|
|
||||||
// implemented
|
|
||||||
reconfigure(unlock_first_keybinds(
|
|
||||||
self.primary_modifier
|
|
||||||
.iter()
|
|
||||||
.map(|m| m.to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(" "),
|
|
||||||
self.secondary_modifier
|
|
||||||
.iter()
|
|
||||||
.map(|m| m.to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(" "),
|
|
||||||
));
|
|
||||||
switch_to_input_mode(&InputMode::Locked);
|
|
||||||
}
|
|
||||||
should_render = true;
|
should_render = true;
|
||||||
}
|
}
|
||||||
} else if key.bare_key == BareKey::Char('l') && key.has_no_modifiers() {
|
} else if key.bare_key == BareKey::Char('l') && key.has_no_modifiers() {
|
||||||
self.remapping_leaders = true;
|
self.remapping_leaders = true;
|
||||||
should_render = true;
|
should_render = true;
|
||||||
} else if key.bare_key == BareKey::Esc && key.has_no_modifiers() {
|
} else if (key.bare_key == BareKey::Esc && key.has_no_modifiers())
|
||||||
|
|| key.is_key_with_ctrl_modifier(BareKey::Char('c'))
|
||||||
|
{
|
||||||
|
close_self();
|
||||||
|
should_render = true;
|
||||||
|
}
|
||||||
|
should_render
|
||||||
|
}
|
||||||
|
fn handle_setup_wizard_key(&mut self, key: KeyWithModifier) -> bool {
|
||||||
|
let mut should_render = false;
|
||||||
|
if self.notification.is_some() {
|
||||||
|
self.notification = None;
|
||||||
|
should_render = true;
|
||||||
|
} else if key.bare_key == BareKey::Down && key.has_no_modifiers() {
|
||||||
|
if self.selected_index.is_none() {
|
||||||
|
self.selected_index = Some(0);
|
||||||
|
} else if self.selected_index < Some(1) {
|
||||||
|
self.selected_index = Some(1);
|
||||||
|
} else {
|
||||||
|
self.selected_index = None;
|
||||||
|
}
|
||||||
|
should_render = true;
|
||||||
|
} else if key.bare_key == BareKey::Up && key.has_no_modifiers() {
|
||||||
|
if self.selected_index.is_none() {
|
||||||
|
self.selected_index = Some(1);
|
||||||
|
} else if self.selected_index == Some(1) {
|
||||||
|
self.selected_index = Some(0);
|
||||||
|
} else {
|
||||||
|
self.selected_index = None;
|
||||||
|
}
|
||||||
|
should_render = true;
|
||||||
|
} else if key.bare_key == BareKey::Enter && key.has_no_modifiers() {
|
||||||
|
if let Some(selected) = self.selected_index.take() {
|
||||||
|
let write_to_disk = true;
|
||||||
|
self.reconfigure(selected, write_to_disk);
|
||||||
|
close_self();
|
||||||
|
} else {
|
||||||
|
self.selected_index = Some(0);
|
||||||
|
should_render = true;
|
||||||
|
}
|
||||||
|
} else if key.bare_key == BareKey::Char('l') && key.has_no_modifiers() {
|
||||||
|
self.remapping_leaders = true;
|
||||||
|
should_render = true;
|
||||||
|
} else if (key.bare_key == BareKey::Esc && key.has_no_modifiers())
|
||||||
|
|| key.is_key_with_ctrl_modifier(BareKey::Char('c'))
|
||||||
|
{
|
||||||
close_self();
|
close_self();
|
||||||
should_render = true;
|
should_render = true;
|
||||||
}
|
}
|
||||||
|
|
@ -412,7 +477,7 @@ impl State {
|
||||||
print_text_with_coordinates(
|
print_text_with_coordinates(
|
||||||
Text::new(title_text).color_range(2, ..),
|
Text::new(title_text).color_range(2, ..),
|
||||||
left_padding,
|
left_padding,
|
||||||
rows.saturating_sub(15) / 2,
|
rows.saturating_sub(self.ui_size) / 2,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
@ -426,7 +491,91 @@ impl State {
|
||||||
print_text_with_coordinates(
|
print_text_with_coordinates(
|
||||||
Text::new(title_text).color_range(2, ..),
|
Text::new(title_text).color_range(2, ..),
|
||||||
left_padding,
|
left_padding,
|
||||||
rows.saturating_sub(15) / 2,
|
rows.saturating_sub(self.ui_size) / 2,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn render_setup_wizard_title(&self, rows: usize, cols: usize, primary_modifier_key_text: &str) {
|
||||||
|
let widths = self.main_screen_widths(primary_modifier_key_text);
|
||||||
|
if cols >= widths.0 {
|
||||||
|
let title_text_1 = "Hi there! How would you like to interact with Zellij?";
|
||||||
|
let title_text_2 = "Not sure? Press <ENTER> to choose Default.";
|
||||||
|
let title_text_3 = "Everything can always be changed later.";
|
||||||
|
let title_text_4 = "Tips appear on screen - you don't need to remember anything.";
|
||||||
|
let left_padding = cols.saturating_sub(widths.0) / 2;
|
||||||
|
let first_row_coords = (rows.saturating_sub(self.ui_size) / 2).saturating_sub(1);
|
||||||
|
print_text_with_coordinates(
|
||||||
|
Text::new(title_text_1).color_range(2, ..),
|
||||||
|
left_padding,
|
||||||
|
first_row_coords,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
print_text_with_coordinates(
|
||||||
|
Text::new(title_text_2)
|
||||||
|
.color_range(0, ..10)
|
||||||
|
.color_range(2, 16..23)
|
||||||
|
.color_range(self.preset_color_index, 34..41),
|
||||||
|
left_padding,
|
||||||
|
first_row_coords + 2,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
print_text_with_coordinates(
|
||||||
|
Text::new(title_text_3),
|
||||||
|
left_padding,
|
||||||
|
first_row_coords + 4,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
print_text_with_coordinates(
|
||||||
|
Text::new(title_text_4),
|
||||||
|
left_padding,
|
||||||
|
first_row_coords + 5,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let title_text_1 = "Hi there! Which do you prefer?";
|
||||||
|
let title_text_2 = "Not sure? Press <ENTER>";
|
||||||
|
let title_text_3 = "Can be changed later. Tips appear";
|
||||||
|
let title_text_4 = "on screen - no need to remember";
|
||||||
|
let left_padding = if cols >= widths.1 {
|
||||||
|
cols.saturating_sub(widths.1) / 2
|
||||||
|
} else {
|
||||||
|
cols.saturating_sub(widths.2) / 2
|
||||||
|
};
|
||||||
|
let first_row_coords = (rows.saturating_sub(self.ui_size) / 2).saturating_sub(1);
|
||||||
|
print_text_with_coordinates(
|
||||||
|
Text::new(title_text_1).color_range(2, ..),
|
||||||
|
left_padding,
|
||||||
|
first_row_coords,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
print_text_with_coordinates(
|
||||||
|
Text::new(title_text_2)
|
||||||
|
.color_range(0, ..10)
|
||||||
|
.color_range(2, 16..23)
|
||||||
|
.color_range(self.preset_color_index, 40..49),
|
||||||
|
left_padding,
|
||||||
|
first_row_coords + 2,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
print_text_with_coordinates(
|
||||||
|
Text::new(title_text_3),
|
||||||
|
left_padding,
|
||||||
|
first_row_coords + 4,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
print_text_with_coordinates(
|
||||||
|
Text::new(title_text_4),
|
||||||
|
left_padding,
|
||||||
|
first_row_coords + 5,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
@ -455,7 +604,7 @@ impl State {
|
||||||
)
|
)
|
||||||
.indent(1),
|
.indent(1),
|
||||||
NestedListItem::new(format!(
|
NestedListItem::new(format!(
|
||||||
"{} t - to enter TAB mode.",
|
"{} t - to enter TAB mode",
|
||||||
primary_modifier_key_text
|
primary_modifier_key_text
|
||||||
))
|
))
|
||||||
.color_range(
|
.color_range(
|
||||||
|
|
@ -488,7 +637,7 @@ impl State {
|
||||||
primary_modifier_key_text_len + 14..primary_modifier_key_text_len + 18,
|
primary_modifier_key_text_len + 14..primary_modifier_key_text_len + 18,
|
||||||
),
|
),
|
||||||
NestedListItem::new(format!(
|
NestedListItem::new(format!(
|
||||||
"{} t - to enter TAB mode.",
|
"{} t - to enter TAB mode",
|
||||||
primary_modifier_key_text
|
primary_modifier_key_text
|
||||||
))
|
))
|
||||||
.indent(1)
|
.indent(1)
|
||||||
|
|
@ -517,7 +666,7 @@ impl State {
|
||||||
primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 10,
|
primary_modifier_key_text_len + 5..primary_modifier_key_text_len + 10,
|
||||||
)
|
)
|
||||||
.indent(1),
|
.indent(1),
|
||||||
NestedListItem::new(format!("{} t - TAB mode.", primary_modifier_key_text))
|
NestedListItem::new(format!("{} t - TAB mode", primary_modifier_key_text))
|
||||||
.color_range(
|
.color_range(
|
||||||
self.primary_leader_key_color_index,
|
self.primary_leader_key_color_index,
|
||||||
..primary_modifier_key_text_len + 3,
|
..primary_modifier_key_text_len + 3,
|
||||||
|
|
@ -536,9 +685,9 @@ impl State {
|
||||||
}
|
}
|
||||||
let left_padding = cols.saturating_sub(max_width) / 2;
|
let left_padding = cols.saturating_sub(max_width) / 2;
|
||||||
let top_coordinates = if rows > 14 {
|
let top_coordinates = if rows > 14 {
|
||||||
(rows.saturating_sub(15) / 2) + 2
|
(rows.saturating_sub(self.ui_size) / 2) + 2
|
||||||
} else {
|
} else {
|
||||||
(rows.saturating_sub(15) / 2) + 1
|
(rows.saturating_sub(self.ui_size) / 2) + 1
|
||||||
};
|
};
|
||||||
print_nested_list_with_coordinates(
|
print_nested_list_with_coordinates(
|
||||||
list_items,
|
list_items,
|
||||||
|
|
@ -578,7 +727,7 @@ impl State {
|
||||||
primary_modifier_key_text_len + 16..primary_modifier_key_text_len + 21,
|
primary_modifier_key_text_len + 16..primary_modifier_key_text_len + 21,
|
||||||
),
|
),
|
||||||
NestedListItem::new(format!(
|
NestedListItem::new(format!(
|
||||||
"{} g + t to enter TAB mode.",
|
"{} g + t to enter TAB mode",
|
||||||
primary_modifier_key_text
|
primary_modifier_key_text
|
||||||
))
|
))
|
||||||
.indent(1)
|
.indent(1)
|
||||||
|
|
@ -623,7 +772,7 @@ impl State {
|
||||||
)
|
)
|
||||||
.indent(1),
|
.indent(1),
|
||||||
NestedListItem::new(format!(
|
NestedListItem::new(format!(
|
||||||
"{} g + t to enter TAB mode.",
|
"{} g + t to enter TAB mode",
|
||||||
primary_modifier_key_text
|
primary_modifier_key_text
|
||||||
))
|
))
|
||||||
.color_range(
|
.color_range(
|
||||||
|
|
@ -664,7 +813,7 @@ impl State {
|
||||||
primary_modifier_key_text_len + 7..primary_modifier_key_text_len + 11,
|
primary_modifier_key_text_len + 7..primary_modifier_key_text_len + 11,
|
||||||
)
|
)
|
||||||
.indent(1),
|
.indent(1),
|
||||||
NestedListItem::new(format!("{} g + t TAB mode.", primary_modifier_key_text))
|
NestedListItem::new(format!("{} g + t TAB mode", primary_modifier_key_text))
|
||||||
.color_range(
|
.color_range(
|
||||||
self.primary_leader_key_color_index,
|
self.primary_leader_key_color_index,
|
||||||
..primary_modifier_key_text_len + 3,
|
..primary_modifier_key_text_len + 3,
|
||||||
|
|
@ -687,9 +836,9 @@ impl State {
|
||||||
}
|
}
|
||||||
let left_padding = cols.saturating_sub(max_width) / 2;
|
let left_padding = cols.saturating_sub(max_width) / 2;
|
||||||
let top_coordinates = if rows > 14 {
|
let top_coordinates = if rows > 14 {
|
||||||
(rows.saturating_sub(15) / 2) + 7
|
(rows.saturating_sub(self.ui_size) / 2) + 7
|
||||||
} else {
|
} else {
|
||||||
(rows.saturating_sub(15) / 2) + 5
|
(rows.saturating_sub(self.ui_size) / 2) + 5
|
||||||
};
|
};
|
||||||
print_nested_list_with_coordinates(
|
print_nested_list_with_coordinates(
|
||||||
list_items,
|
list_items,
|
||||||
|
|
@ -710,14 +859,14 @@ impl State {
|
||||||
let primary_modifier_key_text_len = primary_modifier_key_text.chars().count();
|
let primary_modifier_key_text_len = primary_modifier_key_text.chars().count();
|
||||||
let secondary_modifier_key_text_len = secondary_modifier_key_text.chars().count();
|
let secondary_modifier_key_text_len = secondary_modifier_key_text.chars().count();
|
||||||
let top_coordinates = if rows > 14 {
|
let top_coordinates = if rows > 14 {
|
||||||
(rows.saturating_sub(15) / 2) + 12
|
(rows.saturating_sub(self.ui_size) / 2) + 12
|
||||||
} else {
|
} else {
|
||||||
(rows.saturating_sub(15) / 2) + 9
|
(rows.saturating_sub(self.ui_size) / 2) + 9
|
||||||
};
|
};
|
||||||
|
|
||||||
if cols >= widths.0 {
|
if cols >= widths.0 {
|
||||||
let leader_key_text = format!(
|
let leader_key_text = format!(
|
||||||
"Leader keys: {} - modes, {} - quicknav and shortcuts.",
|
"Leader keys: {} - modes, {} - quicknav and shortcuts",
|
||||||
primary_modifier_key_text, secondary_modifier_key_text
|
primary_modifier_key_text, secondary_modifier_key_text
|
||||||
);
|
);
|
||||||
let left_padding = cols.saturating_sub(widths.0) / 2;
|
let left_padding = cols.saturating_sub(widths.0) / 2;
|
||||||
|
|
@ -767,12 +916,12 @@ impl State {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
fn render_warning_if_needed(&self, rows: usize, cols: usize, primary_modifier_key_text: &str) {
|
fn render_info_line(&self, rows: usize, cols: usize, primary_modifier_key_text: &str) {
|
||||||
let widths = self.main_screen_widths(primary_modifier_key_text);
|
let widths = self.main_screen_widths(primary_modifier_key_text);
|
||||||
let top_coordinates = if rows > 14 {
|
let top_coordinates = if rows > 14 {
|
||||||
(rows.saturating_sub(15) / 2) + 14
|
(rows.saturating_sub(self.ui_size) / 2) + 14
|
||||||
} else {
|
} else {
|
||||||
(rows.saturating_sub(15) / 2) + 10
|
(rows.saturating_sub(self.ui_size) / 2) + 10
|
||||||
};
|
};
|
||||||
let left_padding = if cols >= widths.0 {
|
let left_padding = if cols >= widths.0 {
|
||||||
cols.saturating_sub(widths.0) / 2
|
cols.saturating_sub(widths.0) / 2
|
||||||
|
|
@ -781,7 +930,15 @@ impl State {
|
||||||
} else {
|
} else {
|
||||||
cols.saturating_sub(widths.2) / 2
|
cols.saturating_sub(widths.2) / 2
|
||||||
};
|
};
|
||||||
if let Some(warning_text) = self.warning_text(cols) {
|
if let Some(notification) = &self.notification {
|
||||||
|
print_text_with_coordinates(
|
||||||
|
Text::new(notification).color_range(3, ..),
|
||||||
|
left_padding,
|
||||||
|
top_coordinates,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
} else if let Some(warning_text) = self.warning_text(cols) {
|
||||||
print_text_with_coordinates(
|
print_text_with_coordinates(
|
||||||
Text::new(warning_text).color_range(3, ..),
|
Text::new(warning_text).color_range(3, ..),
|
||||||
left_padding,
|
left_padding,
|
||||||
|
|
@ -791,24 +948,56 @@ impl State {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fn render_help_text_main(&self, rows: usize, cols: usize, primary_modifier_key_text: &str) {
|
fn render_help_text_main(&self, rows: usize, cols: usize) {
|
||||||
let widths = self.main_screen_widths(primary_modifier_key_text);
|
let full_help_text = "Help: <↓↑> - navigate, <ENTER> - apply, <SPACE> - apply & save, <l> - leaders, <ESC> - close";
|
||||||
if cols >= widths.0 {
|
let short_help_text = "Help: <↓↑> / <ENTER> / <SPACE> / <l> / <ESC>";
|
||||||
let help_text = "Help: <↓↑/ENTER> - navigate/select, <l> - leaders, <ESC> - close";
|
if cols >= full_help_text.chars().count() {
|
||||||
print_text_with_coordinates(
|
print_text_with_coordinates(
|
||||||
Text::new(help_text)
|
Text::new(full_help_text)
|
||||||
.color_range(2, 6..16)
|
.color_range(2, 6..10)
|
||||||
.color_range(2, 36..39)
|
.color_range(2, 23..30)
|
||||||
.color_range(2, 51..56),
|
.color_range(2, 40..47)
|
||||||
|
.color_range(2, 64..67)
|
||||||
|
.color_range(2, 79..84),
|
||||||
0,
|
0,
|
||||||
rows,
|
rows,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let help_text = "Help: <↓↑> / <ENTER> / <l> / <ESC>";
|
|
||||||
print_text_with_coordinates(
|
print_text_with_coordinates(
|
||||||
Text::new(help_text)
|
Text::new(short_help_text)
|
||||||
|
.color_range(2, 6..10)
|
||||||
|
.color_range(2, 13..20)
|
||||||
|
.color_range(2, 23..30)
|
||||||
|
.color_range(2, 33..36)
|
||||||
|
.color_range(2, 39..44),
|
||||||
|
0,
|
||||||
|
rows,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn render_help_text_setup_wizard(&self, rows: usize, cols: usize) {
|
||||||
|
let full_help_text =
|
||||||
|
"Help: <↓↑> - navigate, <ENTER> - apply & save, <l> - change leaders, <ESC> - close";
|
||||||
|
let short_help_text = "Help: <↓↑> / <ENTER> / <l> / <ESC>";
|
||||||
|
if cols >= full_help_text.chars().count() {
|
||||||
|
print_text_with_coordinates(
|
||||||
|
Text::new(full_help_text)
|
||||||
|
.color_range(2, 6..10)
|
||||||
|
.color_range(2, 23..30)
|
||||||
|
.color_range(2, 47..50)
|
||||||
|
.color_range(2, 69..74),
|
||||||
|
0,
|
||||||
|
rows,
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
print_text_with_coordinates(
|
||||||
|
Text::new(short_help_text)
|
||||||
.color_range(2, 6..10)
|
.color_range(2, 6..10)
|
||||||
.color_range(2, 13..20)
|
.color_range(2, 13..20)
|
||||||
.color_range(2, 23..26)
|
.color_range(2, 23..26)
|
||||||
|
|
@ -892,8 +1081,23 @@ impl State {
|
||||||
&primary_modifier_key_text,
|
&primary_modifier_key_text,
|
||||||
&secondary_modifier_key_text,
|
&secondary_modifier_key_text,
|
||||||
);
|
);
|
||||||
self.render_warning_if_needed(rows, cols, &primary_modifier_key_text);
|
self.render_info_line(rows, cols, &primary_modifier_key_text);
|
||||||
self.render_help_text_main(rows, cols, &primary_modifier_key_text);
|
self.render_help_text_main(rows, cols);
|
||||||
|
}
|
||||||
|
fn render_setup_wizard_screen(&mut self, rows: usize, cols: usize) {
|
||||||
|
let primary_modifier_key_text = self.primary_modifier_text();
|
||||||
|
let secondary_modifier_key_text = self.secondary_modifier_text();
|
||||||
|
self.render_setup_wizard_title(rows, cols, &primary_modifier_key_text);
|
||||||
|
self.render_first_bulletin(rows + 8, cols, &primary_modifier_key_text);
|
||||||
|
self.render_second_bulletin(rows + 8, cols, &primary_modifier_key_text);
|
||||||
|
self.render_leader_keys_indication(
|
||||||
|
rows + 8,
|
||||||
|
cols,
|
||||||
|
&primary_modifier_key_text,
|
||||||
|
&secondary_modifier_key_text,
|
||||||
|
);
|
||||||
|
self.render_info_line(rows + 8, cols, &primary_modifier_key_text);
|
||||||
|
self.render_help_text_setup_wizard(rows + 8, cols);
|
||||||
}
|
}
|
||||||
fn warning_text(&self, max_width: usize) -> Option<String> {
|
fn warning_text(&self, max_width: usize) -> Option<String> {
|
||||||
if self.needs_kitty_support() {
|
if self.needs_kitty_support() {
|
||||||
|
|
@ -921,6 +1125,47 @@ impl State {
|
||||||
|| self.primary_modifier.contains(&KeyModifier::Super)
|
|| self.primary_modifier.contains(&KeyModifier::Super)
|
||||||
|| self.secondary_modifier.contains(&KeyModifier::Super)
|
|| self.secondary_modifier.contains(&KeyModifier::Super)
|
||||||
}
|
}
|
||||||
|
fn reconfigure(&self, selected: usize, write_to_disk: bool) {
|
||||||
|
if selected == 0 {
|
||||||
|
// TODO: these should be part of a "transaction" when they are
|
||||||
|
// implemented
|
||||||
|
reconfigure(
|
||||||
|
default_keybinds(
|
||||||
|
self.primary_modifier
|
||||||
|
.iter()
|
||||||
|
.map(|m| m.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" "),
|
||||||
|
self.secondary_modifier
|
||||||
|
.iter()
|
||||||
|
.map(|m| m.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" "),
|
||||||
|
),
|
||||||
|
write_to_disk,
|
||||||
|
);
|
||||||
|
switch_to_input_mode(&InputMode::Normal);
|
||||||
|
} else if selected == 1 {
|
||||||
|
// TODO: these should be part of a "transaction" when they are
|
||||||
|
// implemented
|
||||||
|
reconfigure(
|
||||||
|
unlock_first_keybinds(
|
||||||
|
self.primary_modifier
|
||||||
|
.iter()
|
||||||
|
.map(|m| m.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" "),
|
||||||
|
self.secondary_modifier
|
||||||
|
.iter()
|
||||||
|
.map(|m| m.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(" "),
|
||||||
|
),
|
||||||
|
write_to_disk,
|
||||||
|
);
|
||||||
|
switch_to_input_mode(&InputMode::Locked);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unlock_first_keybinds(primary_modifier: String, secondary_modifier: String) -> String {
|
fn unlock_first_keybinds(primary_modifier: String, secondary_modifier: String) -> String {
|
||||||
|
|
|
||||||
|
|
@ -332,6 +332,7 @@ impl ZellijPlugin for State {
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
BareKey::Char('0') if key.has_modifiers(&[KeyModifier::Ctrl]) => {
|
BareKey::Char('0') if key.has_modifiers(&[KeyModifier::Ctrl]) => {
|
||||||
|
let write_to_disk = true;
|
||||||
reconfigure(
|
reconfigure(
|
||||||
"
|
"
|
||||||
keybinds {
|
keybinds {
|
||||||
|
|
@ -341,6 +342,7 @@ impl ZellijPlugin for State {
|
||||||
}
|
}
|
||||||
"
|
"
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
|
write_to_disk,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
BareKey::Char('a') if key.has_modifiers(&[KeyModifier::Alt]) => {
|
BareKey::Char('a') if key.has_modifiers(&[KeyModifier::Alt]) => {
|
||||||
|
|
|
||||||
|
|
@ -386,19 +386,25 @@ fn attach_with_session_name(
|
||||||
pub(crate) fn start_client(opts: CliArgs) {
|
pub(crate) fn start_client(opts: CliArgs) {
|
||||||
// look for old YAML config/layout/theme files and convert them to KDL
|
// look for old YAML config/layout/theme files and convert them to KDL
|
||||||
convert_old_yaml_files(&opts);
|
convert_old_yaml_files(&opts);
|
||||||
let (config, layout, config_options, config_without_layout, config_options_without_layout) =
|
let (
|
||||||
match Setup::from_cli_args(&opts) {
|
config,
|
||||||
Ok(results) => results,
|
layout,
|
||||||
Err(e) => {
|
config_options,
|
||||||
if let ConfigError::KdlError(error) = e {
|
mut config_without_layout,
|
||||||
let report: Report = error.into();
|
mut config_options_without_layout,
|
||||||
eprintln!("{:?}", report);
|
) = match Setup::from_cli_args(&opts) {
|
||||||
} else {
|
Ok(results) => results,
|
||||||
eprintln!("{}", e);
|
Err(e) => {
|
||||||
}
|
if let ConfigError::KdlError(error) = e {
|
||||||
process::exit(1);
|
let report: Report = error.into();
|
||||||
},
|
eprintln!("{:?}", report);
|
||||||
};
|
} else {
|
||||||
|
eprintln!("{}", e);
|
||||||
|
}
|
||||||
|
process::exit(1);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
let mut reconnect_to_session: Option<ConnectToSession> = None;
|
let mut reconnect_to_session: Option<ConnectToSession> = None;
|
||||||
let os_input = get_os_input(get_client_os_input);
|
let os_input = get_os_input(get_client_os_input);
|
||||||
loop {
|
loop {
|
||||||
|
|
@ -415,6 +421,11 @@ pub(crate) fn start_client(opts: CliArgs) {
|
||||||
// untested and pretty involved function
|
// untested and pretty involved function
|
||||||
//
|
//
|
||||||
// ideally, we should write tests for this whole function and refctor it
|
// ideally, we should write tests for this whole function and refctor it
|
||||||
|
reload_config_from_disk(
|
||||||
|
&mut config_without_layout,
|
||||||
|
&mut config_options_without_layout,
|
||||||
|
&opts,
|
||||||
|
);
|
||||||
if reconnect_to_session.name.is_some() {
|
if reconnect_to_session.name.is_some() {
|
||||||
opts.command = Some(Command::Sessions(Sessions::Attach {
|
opts.command = Some(Command::Sessions(Sessions::Attach {
|
||||||
session_name: reconnect_to_session.name.clone(),
|
session_name: reconnect_to_session.name.clone(),
|
||||||
|
|
@ -711,3 +722,19 @@ pub(crate) fn list_aliases(opts: CliArgs) {
|
||||||
}
|
}
|
||||||
process::exit(0);
|
process::exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reload_config_from_disk(
|
||||||
|
config_without_layout: &mut Config,
|
||||||
|
config_options_without_layout: &mut Options,
|
||||||
|
opts: &CliArgs,
|
||||||
|
) {
|
||||||
|
match Setup::from_cli_args(&opts) {
|
||||||
|
Ok((_, _, _, reloaded_config_without_layout, reloaded_config_options_without_layout)) => {
|
||||||
|
*config_without_layout = reloaded_config_without_layout;
|
||||||
|
*config_options_without_layout = reloaded_config_options_without_layout;
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to reload config: {}", e);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ use log::info;
|
||||||
use std::env::current_exe;
|
use std::env::current_exe;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::path::PathBuf;
|
||||||
use std::process::Command;
|
use std::process::Command;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
|
|
@ -53,6 +54,7 @@ pub(crate) enum ClientInstruction {
|
||||||
UnblockCliPipeInput(String), // String -> pipe name
|
UnblockCliPipeInput(String), // String -> pipe name
|
||||||
CliPipeOutput(String, String), // String -> pipe name, String -> output
|
CliPipeOutput(String, String), // String -> pipe name, String -> output
|
||||||
QueryTerminalSize,
|
QueryTerminalSize,
|
||||||
|
WriteConfigToDisk { config: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ServerToClientMsg> for ClientInstruction {
|
impl From<ServerToClientMsg> for ClientInstruction {
|
||||||
|
|
@ -75,6 +77,9 @@ impl From<ServerToClientMsg> for ClientInstruction {
|
||||||
ClientInstruction::CliPipeOutput(pipe_name, output)
|
ClientInstruction::CliPipeOutput(pipe_name, output)
|
||||||
},
|
},
|
||||||
ServerToClientMsg::QueryTerminalSize => ClientInstruction::QueryTerminalSize,
|
ServerToClientMsg::QueryTerminalSize => ClientInstruction::QueryTerminalSize,
|
||||||
|
ServerToClientMsg::WriteConfigToDisk { config } => {
|
||||||
|
ClientInstruction::WriteConfigToDisk { config }
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -97,6 +102,7 @@ impl From<&ClientInstruction> for ClientContext {
|
||||||
ClientInstruction::UnblockCliPipeInput(..) => ClientContext::UnblockCliPipeInput,
|
ClientInstruction::UnblockCliPipeInput(..) => ClientContext::UnblockCliPipeInput,
|
||||||
ClientInstruction::CliPipeOutput(..) => ClientContext::CliPipeOutput,
|
ClientInstruction::CliPipeOutput(..) => ClientContext::CliPipeOutput,
|
||||||
ClientInstruction::QueryTerminalSize => ClientContext::QueryTerminalSize,
|
ClientInstruction::QueryTerminalSize => ClientContext::QueryTerminalSize,
|
||||||
|
ClientInstruction::WriteConfigToDisk { .. } => ClientContext::WriteConfigToDisk,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -158,8 +164,8 @@ pub(crate) enum InputInstruction {
|
||||||
pub fn start_client(
|
pub fn start_client(
|
||||||
mut os_input: Box<dyn ClientOsApi>,
|
mut os_input: Box<dyn ClientOsApi>,
|
||||||
opts: CliArgs,
|
opts: CliArgs,
|
||||||
config: Config,
|
config: Config, // saved to disk (or default?)
|
||||||
config_options: Options,
|
config_options: Options, // CLI options merged into (getting priority over) saved config options
|
||||||
info: ClientInfo,
|
info: ClientInfo,
|
||||||
layout: Option<Layout>,
|
layout: Option<Layout>,
|
||||||
tab_position_to_focus: Option<usize>,
|
tab_position_to_focus: Option<usize>,
|
||||||
|
|
@ -218,7 +224,6 @@ pub fn start_client(
|
||||||
rounded_corners: config.ui.pane_frames.rounded_corners,
|
rounded_corners: config.ui.pane_frames.rounded_corners,
|
||||||
hide_session_name: config.ui.pane_frames.hide_session_name,
|
hide_session_name: config.ui.pane_frames.hide_session_name,
|
||||||
},
|
},
|
||||||
keybinds: config.keybinds.clone(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let create_ipc_pipe = || -> std::path::PathBuf {
|
let create_ipc_pipe = || -> std::path::PathBuf {
|
||||||
|
|
@ -238,7 +243,8 @@ pub fn start_client(
|
||||||
(
|
(
|
||||||
ClientToServerMsg::AttachClient(
|
ClientToServerMsg::AttachClient(
|
||||||
client_attributes,
|
client_attributes,
|
||||||
config_options,
|
config.clone(),
|
||||||
|
config_options.clone(),
|
||||||
tab_position_to_focus,
|
tab_position_to_focus,
|
||||||
pane_id_to_focus,
|
pane_id_to_focus,
|
||||||
),
|
),
|
||||||
|
|
@ -251,14 +257,25 @@ pub fn start_client(
|
||||||
let ipc_pipe = create_ipc_pipe();
|
let ipc_pipe = create_ipc_pipe();
|
||||||
|
|
||||||
spawn_server(&*ipc_pipe, opts.debug).unwrap();
|
spawn_server(&*ipc_pipe, opts.debug).unwrap();
|
||||||
|
let successfully_written_config =
|
||||||
|
Config::write_config_to_disk_if_it_does_not_exist(config.to_string(true), &opts);
|
||||||
|
// if we successfully wrote the config to disk, it means two things:
|
||||||
|
// 1. It did not exist beforehand
|
||||||
|
// 2. The config folder is writeable
|
||||||
|
//
|
||||||
|
// If these two are true, we should launch the setup wizard, if even one of them is
|
||||||
|
// false, we should never launch it.
|
||||||
|
let should_launch_setup_wizard = successfully_written_config;
|
||||||
|
|
||||||
(
|
(
|
||||||
ClientToServerMsg::NewClient(
|
ClientToServerMsg::NewClient(
|
||||||
client_attributes,
|
client_attributes,
|
||||||
Box::new(opts),
|
Box::new(opts.clone()),
|
||||||
|
Box::new(config.clone()),
|
||||||
Box::new(config_options.clone()),
|
Box::new(config_options.clone()),
|
||||||
Box::new(layout.unwrap()),
|
Box::new(layout.unwrap()),
|
||||||
Box::new(config.plugins.clone()),
|
Box::new(config.plugins.clone()),
|
||||||
|
should_launch_setup_wizard,
|
||||||
),
|
),
|
||||||
ipc_pipe,
|
ipc_pipe,
|
||||||
)
|
)
|
||||||
|
|
@ -522,6 +539,23 @@ pub fn start_client(
|
||||||
os_input.get_terminal_size_using_fd(0),
|
os_input.get_terminal_size_using_fd(0),
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
ClientInstruction::WriteConfigToDisk { config } => {
|
||||||
|
match Config::write_config_to_disk(config, &opts) {
|
||||||
|
Ok(written_config) => {
|
||||||
|
let _ = os_input
|
||||||
|
.send_to_server(ClientToServerMsg::ConfigWrittenToDisk(written_config));
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
let error_path = e
|
||||||
|
.as_ref()
|
||||||
|
.map(|p| p.display().to_string())
|
||||||
|
.unwrap_or_else(String::new);
|
||||||
|
log::error!("Failed to write config to disk: {}", error_path);
|
||||||
|
let _ = os_input
|
||||||
|
.send_to_server(ClientToServerMsg::FailedToWriteConfigToDisk(e));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -584,7 +618,6 @@ pub fn start_server_detached(
|
||||||
rounded_corners: config.ui.pane_frames.rounded_corners,
|
rounded_corners: config.ui.pane_frames.rounded_corners,
|
||||||
hide_session_name: config.ui.pane_frames.hide_session_name,
|
hide_session_name: config.ui.pane_frames.hide_session_name,
|
||||||
},
|
},
|
||||||
keybinds: config.keybinds.clone(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let create_ipc_pipe = || -> std::path::PathBuf {
|
let create_ipc_pipe = || -> std::path::PathBuf {
|
||||||
|
|
@ -602,14 +635,18 @@ pub fn start_server_detached(
|
||||||
let ipc_pipe = create_ipc_pipe();
|
let ipc_pipe = create_ipc_pipe();
|
||||||
|
|
||||||
spawn_server(&*ipc_pipe, opts.debug).unwrap();
|
spawn_server(&*ipc_pipe, opts.debug).unwrap();
|
||||||
|
let should_launch_setup_wizard = false; // no setup wizard when starting a detached
|
||||||
|
// server
|
||||||
|
|
||||||
(
|
(
|
||||||
ClientToServerMsg::NewClient(
|
ClientToServerMsg::NewClient(
|
||||||
client_attributes,
|
client_attributes,
|
||||||
Box::new(opts),
|
Box::new(opts),
|
||||||
|
Box::new(config.clone()),
|
||||||
Box::new(config_options.clone()),
|
Box::new(config_options.clone()),
|
||||||
Box::new(layout.unwrap()),
|
Box::new(layout.unwrap()),
|
||||||
Box::new(config.plugins.clone()),
|
Box::new(config.plugins.clone()),
|
||||||
|
should_launch_setup_wizard,
|
||||||
),
|
),
|
||||||
ipc_pipe,
|
ipc_pipe,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ mod ui;
|
||||||
use background_jobs::{background_jobs_main, BackgroundJob};
|
use background_jobs::{background_jobs_main, BackgroundJob};
|
||||||
use log::info;
|
use log::info;
|
||||||
use pty_writer::{pty_writer_main, PtyWriteInstruction};
|
use pty_writer::{pty_writer_main, PtyWriteInstruction};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{BTreeMap, HashMap, HashSet};
|
||||||
use std::{
|
use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, RwLock},
|
sync::{Arc, RwLock},
|
||||||
|
|
@ -28,7 +28,7 @@ use zellij_utils::envs;
|
||||||
use zellij_utils::nix::sys::stat::{umask, Mode};
|
use zellij_utils::nix::sys::stat::{umask, Mode};
|
||||||
use zellij_utils::pane_size::Size;
|
use zellij_utils::pane_size::Size;
|
||||||
|
|
||||||
use wasmtime::{Config, Engine, Strategy};
|
use wasmtime::{Config as WasmtimeConfig, Engine, Strategy};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
os_input_output::ServerOsApi,
|
os_input_output::ServerOsApi,
|
||||||
|
|
@ -47,9 +47,10 @@ use zellij_utils::{
|
||||||
home::{default_layout_dir, get_default_data_dir},
|
home::{default_layout_dir, get_default_data_dir},
|
||||||
input::{
|
input::{
|
||||||
command::{RunCommand, TerminalAction},
|
command::{RunCommand, TerminalAction},
|
||||||
|
config::Config,
|
||||||
get_mode_info,
|
get_mode_info,
|
||||||
keybinds::Keybinds,
|
keybinds::Keybinds,
|
||||||
layout::Layout,
|
layout::{FloatingPaneLayout, Layout, PercentOrFixed, PluginAlias, Run, RunPluginOrAlias},
|
||||||
options::Options,
|
options::Options,
|
||||||
plugins::PluginAliases,
|
plugins::PluginAliases,
|
||||||
},
|
},
|
||||||
|
|
@ -64,9 +65,11 @@ pub enum ServerInstruction {
|
||||||
NewClient(
|
NewClient(
|
||||||
ClientAttributes,
|
ClientAttributes,
|
||||||
Box<CliArgs>,
|
Box<CliArgs>,
|
||||||
Box<Options>,
|
Box<Config>, // represents the saved config
|
||||||
|
Box<Options>, // represents the runtime configuration options
|
||||||
Box<Layout>,
|
Box<Layout>,
|
||||||
Box<PluginAliases>,
|
Box<PluginAliases>,
|
||||||
|
bool, // should launch setup wizard
|
||||||
ClientId,
|
ClientId,
|
||||||
),
|
),
|
||||||
Render(Option<HashMap<ClientId, String>>),
|
Render(Option<HashMap<ClientId, String>>),
|
||||||
|
|
@ -78,7 +81,8 @@ pub enum ServerInstruction {
|
||||||
DetachSession(Vec<ClientId>),
|
DetachSession(Vec<ClientId>),
|
||||||
AttachClient(
|
AttachClient(
|
||||||
ClientAttributes,
|
ClientAttributes,
|
||||||
Options,
|
Config, // represents the saved config
|
||||||
|
Options, // represents the runtime configuration options
|
||||||
Option<usize>, // tab position to focus
|
Option<usize>, // tab position to focus
|
||||||
Option<(u32, bool)>, // (pane_id, is_plugin) => pane_id to focus
|
Option<(u32, bool)>, // (pane_id, is_plugin) => pane_id to focus
|
||||||
ClientId,
|
ClientId,
|
||||||
|
|
@ -97,7 +101,13 @@ pub enum ServerInstruction {
|
||||||
DisconnectAllClientsExcept(ClientId),
|
DisconnectAllClientsExcept(ClientId),
|
||||||
ChangeMode(ClientId, InputMode),
|
ChangeMode(ClientId, InputMode),
|
||||||
ChangeModeForAllClients(InputMode),
|
ChangeModeForAllClients(InputMode),
|
||||||
Reconfigure(ClientId, String), // String -> stringified configuration
|
Reconfigure {
|
||||||
|
client_id: ClientId,
|
||||||
|
config: String,
|
||||||
|
write_config_to_disk: bool,
|
||||||
|
},
|
||||||
|
ConfigWrittenToDisk(ClientId, Config),
|
||||||
|
FailedToWriteConfigToDisk(ClientId, Option<PathBuf>), // Pathbuf - file we failed to write
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&ServerInstruction> for ServerContext {
|
impl From<&ServerInstruction> for ServerContext {
|
||||||
|
|
@ -129,7 +139,11 @@ impl From<&ServerInstruction> for ServerContext {
|
||||||
ServerInstruction::ChangeModeForAllClients(..) => {
|
ServerInstruction::ChangeModeForAllClients(..) => {
|
||||||
ServerContext::ChangeModeForAllClients
|
ServerContext::ChangeModeForAllClients
|
||||||
},
|
},
|
||||||
ServerInstruction::Reconfigure(..) => ServerContext::Reconfigure,
|
ServerInstruction::Reconfigure { .. } => ServerContext::Reconfigure,
|
||||||
|
ServerInstruction::ConfigWrittenToDisk(..) => ServerContext::ConfigWrittenToDisk,
|
||||||
|
ServerInstruction::FailedToWriteConfigToDisk(..) => {
|
||||||
|
ServerContext::FailedToWriteConfigToDisk
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -140,16 +154,83 @@ impl ErrorInstruction for ServerInstruction {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub(crate) struct SessionConfiguration {
|
||||||
|
runtime_config: HashMap<ClientId, Config>, // if present, overrides the saved_config
|
||||||
|
saved_config: HashMap<ClientId, Config>, // config guaranteed to have been saved to disk
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SessionConfiguration {
|
||||||
|
pub fn new_saved_config(&mut self, client_id: ClientId, mut new_saved_config: Config) {
|
||||||
|
self.saved_config
|
||||||
|
.insert(client_id, new_saved_config.clone());
|
||||||
|
if let Some(runtime_config) = self.runtime_config.get_mut(&client_id) {
|
||||||
|
match new_saved_config.merge(runtime_config.clone()) {
|
||||||
|
Ok(_) => {
|
||||||
|
*runtime_config = new_saved_config;
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to update runtime config: {}", e);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: handle change by propagating to all the relevant places
|
||||||
|
}
|
||||||
|
pub fn set_client_saved_configuration(&mut self, client_id: ClientId, client_config: Config) {
|
||||||
|
self.saved_config.insert(client_id, client_config);
|
||||||
|
}
|
||||||
|
pub fn set_client_runtime_configuration(&mut self, client_id: ClientId, client_config: Config) {
|
||||||
|
self.runtime_config.insert(client_id, client_config);
|
||||||
|
}
|
||||||
|
pub fn get_client_keybinds(&self, client_id: &ClientId) -> Keybinds {
|
||||||
|
self.runtime_config
|
||||||
|
.get(client_id)
|
||||||
|
.or_else(|| self.saved_config.get(client_id))
|
||||||
|
.map(|c| c.keybinds.clone())
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
pub fn get_client_configuration(&self, client_id: &ClientId) -> Config {
|
||||||
|
self.runtime_config
|
||||||
|
.get(client_id)
|
||||||
|
.or_else(|| self.saved_config.get(client_id))
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
pub fn reconfigure_runtime_config(
|
||||||
|
&mut self,
|
||||||
|
client_id: &ClientId,
|
||||||
|
stringified_config: String,
|
||||||
|
) -> (Option<Config>, bool) {
|
||||||
|
// bool is whether the config changed
|
||||||
|
let mut full_reconfigured_config = None;
|
||||||
|
let mut config_changed = false;
|
||||||
|
let current_client_configuration = self.get_client_configuration(client_id);
|
||||||
|
match Config::from_kdl(
|
||||||
|
&stringified_config,
|
||||||
|
Some(current_client_configuration.clone()),
|
||||||
|
) {
|
||||||
|
Ok(new_config) => {
|
||||||
|
config_changed = current_client_configuration != new_config;
|
||||||
|
full_reconfigured_config = Some(new_config.clone());
|
||||||
|
self.runtime_config.insert(*client_id, new_config);
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to reconfigure runtime config: {}", e);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
(full_reconfigured_config, config_changed)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct SessionMetaData {
|
pub(crate) struct SessionMetaData {
|
||||||
pub senders: ThreadSenders,
|
pub senders: ThreadSenders,
|
||||||
pub capabilities: PluginCapabilities,
|
pub capabilities: PluginCapabilities,
|
||||||
pub client_attributes: ClientAttributes,
|
pub client_attributes: ClientAttributes,
|
||||||
pub default_shell: Option<TerminalAction>,
|
pub default_shell: Option<TerminalAction>,
|
||||||
pub layout: Box<Layout>,
|
pub layout: Box<Layout>,
|
||||||
pub config_options: Box<Options>,
|
pub current_input_modes: HashMap<ClientId, InputMode>,
|
||||||
pub client_keybinds: HashMap<ClientId, Keybinds>,
|
pub session_configuration: SessionConfiguration,
|
||||||
pub client_input_modes: HashMap<ClientId, InputMode>,
|
|
||||||
pub default_mode: HashMap<ClientId, InputMode>,
|
|
||||||
screen_thread: Option<thread::JoinHandle<()>>,
|
screen_thread: Option<thread::JoinHandle<()>>,
|
||||||
pty_thread: Option<thread::JoinHandle<()>>,
|
pty_thread: Option<thread::JoinHandle<()>>,
|
||||||
plugin_thread: Option<thread::JoinHandle<()>>,
|
plugin_thread: Option<thread::JoinHandle<()>>,
|
||||||
|
|
@ -158,53 +239,22 @@ pub(crate) struct SessionMetaData {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SessionMetaData {
|
impl SessionMetaData {
|
||||||
pub fn set_client_keybinds(&mut self, client_id: ClientId, keybinds: Keybinds) {
|
|
||||||
self.client_keybinds.insert(client_id, keybinds);
|
|
||||||
self.client_input_modes.insert(
|
|
||||||
client_id,
|
|
||||||
self.config_options.default_mode.unwrap_or_default(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
pub fn get_client_keybinds_and_mode(
|
pub fn get_client_keybinds_and_mode(
|
||||||
&self,
|
&self,
|
||||||
client_id: &ClientId,
|
client_id: &ClientId,
|
||||||
) -> Option<(&Keybinds, &InputMode)> {
|
) -> Option<(Keybinds, &InputMode)> {
|
||||||
match (
|
let client_keybinds = self.session_configuration.get_client_keybinds(client_id);
|
||||||
self.client_keybinds.get(client_id),
|
match self.current_input_modes.get(client_id) {
|
||||||
self.client_input_modes.get(client_id),
|
Some(client_input_mode) => Some((client_keybinds, client_input_mode)),
|
||||||
) {
|
|
||||||
(Some(client_keybinds), Some(client_input_mode)) => {
|
|
||||||
Some((client_keybinds, client_input_mode))
|
|
||||||
},
|
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn change_mode_for_all_clients(&mut self, input_mode: InputMode) {
|
pub fn change_mode_for_all_clients(&mut self, input_mode: InputMode) {
|
||||||
let all_clients: Vec<ClientId> = self.client_input_modes.keys().copied().collect();
|
let all_clients: Vec<ClientId> = self.current_input_modes.keys().copied().collect();
|
||||||
for client_id in all_clients {
|
for client_id in all_clients {
|
||||||
self.client_input_modes.insert(client_id, input_mode);
|
self.current_input_modes.insert(client_id, input_mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn rebind_keys(&mut self, client_id: ClientId, new_keybinds: String) -> Option<Keybinds> {
|
|
||||||
if let Some(current_keybinds) = self.client_keybinds.get_mut(&client_id) {
|
|
||||||
match Keybinds::from_string(
|
|
||||||
new_keybinds,
|
|
||||||
current_keybinds.clone(),
|
|
||||||
&self.config_options,
|
|
||||||
) {
|
|
||||||
Ok(new_keybinds) => {
|
|
||||||
*current_keybinds = new_keybinds.clone();
|
|
||||||
return Some(new_keybinds);
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Failed to parse keybindings: {}", e);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
log::error!("Failed to bind keys for client: {client_id}");
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for SessionMetaData {
|
impl Drop for SessionMetaData {
|
||||||
|
|
@ -426,44 +476,55 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||||
err_ctx.add_call(ContextType::IPCServer((&instruction).into()));
|
err_ctx.add_call(ContextType::IPCServer((&instruction).into()));
|
||||||
match instruction {
|
match instruction {
|
||||||
ServerInstruction::NewClient(
|
ServerInstruction::NewClient(
|
||||||
|
// TODO: rename to FirstClientConnected?
|
||||||
client_attributes,
|
client_attributes,
|
||||||
opts,
|
opts,
|
||||||
config_options,
|
config,
|
||||||
|
runtime_config_options,
|
||||||
layout,
|
layout,
|
||||||
plugin_aliases,
|
plugin_aliases,
|
||||||
|
should_launch_setup_wizard,
|
||||||
client_id,
|
client_id,
|
||||||
) => {
|
) => {
|
||||||
let session = init_session(
|
let mut session = init_session(
|
||||||
os_input.clone(),
|
os_input.clone(),
|
||||||
to_server.clone(),
|
to_server.clone(),
|
||||||
client_attributes.clone(),
|
client_attributes.clone(),
|
||||||
SessionOptions {
|
SessionOptions {
|
||||||
opts,
|
opts,
|
||||||
layout: layout.clone(),
|
layout: layout.clone(),
|
||||||
config_options: config_options.clone(),
|
config_options: runtime_config_options.clone(),
|
||||||
},
|
},
|
||||||
|
*config.clone(),
|
||||||
plugin_aliases,
|
plugin_aliases,
|
||||||
);
|
);
|
||||||
|
let mut runtime_configuration = config.clone();
|
||||||
|
runtime_configuration.options = *runtime_config_options.clone();
|
||||||
|
session
|
||||||
|
.session_configuration
|
||||||
|
.set_client_saved_configuration(client_id, *config.clone());
|
||||||
|
session
|
||||||
|
.session_configuration
|
||||||
|
.set_client_runtime_configuration(client_id, *runtime_configuration);
|
||||||
|
let default_input_mode = runtime_config_options.default_mode.unwrap_or_default();
|
||||||
|
session
|
||||||
|
.current_input_modes
|
||||||
|
.insert(client_id, default_input_mode);
|
||||||
|
|
||||||
*session_data.write().unwrap() = Some(session);
|
*session_data.write().unwrap() = Some(session);
|
||||||
session_data
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.set_client_keybinds(client_id, client_attributes.keybinds.clone());
|
|
||||||
session_state
|
session_state
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.set_client_size(client_id, client_attributes.size);
|
.set_client_size(client_id, client_attributes.size);
|
||||||
|
|
||||||
let default_shell = config_options.default_shell.map(|shell| {
|
let default_shell = runtime_config_options.default_shell.map(|shell| {
|
||||||
TerminalAction::RunCommand(RunCommand {
|
TerminalAction::RunCommand(RunCommand {
|
||||||
command: shell,
|
command: shell,
|
||||||
cwd: config_options.default_cwd.clone(),
|
cwd: config.options.default_cwd.clone(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
let cwd = config_options.default_cwd;
|
let cwd = runtime_config_options.default_cwd;
|
||||||
|
|
||||||
let spawn_tabs = |tab_layout, floating_panes_layout, tab_name, swap_layouts| {
|
let spawn_tabs = |tab_layout, floating_panes_layout, tab_name, swap_layouts| {
|
||||||
session_data
|
session_data
|
||||||
|
|
@ -511,9 +572,17 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
let mut floating_panes =
|
||||||
|
layout.template.map(|t| t.1).clone().unwrap_or_default();
|
||||||
|
if should_launch_setup_wizard {
|
||||||
|
// we only do this here (and only once) because otherwise it will be
|
||||||
|
// intrusive
|
||||||
|
let setup_wizard = setup_wizard_floating_pane();
|
||||||
|
floating_panes.push(setup_wizard);
|
||||||
|
}
|
||||||
spawn_tabs(
|
spawn_tabs(
|
||||||
None,
|
None,
|
||||||
layout.template.map(|t| t.1).clone().unwrap_or_default(),
|
floating_panes,
|
||||||
None,
|
None,
|
||||||
(
|
(
|
||||||
layout.swap_tiled_layouts.clone(),
|
layout.swap_tiled_layouts.clone(),
|
||||||
|
|
@ -532,14 +601,29 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||||
},
|
},
|
||||||
ServerInstruction::AttachClient(
|
ServerInstruction::AttachClient(
|
||||||
attrs,
|
attrs,
|
||||||
options,
|
config,
|
||||||
|
runtime_config_options,
|
||||||
tab_position_to_focus,
|
tab_position_to_focus,
|
||||||
pane_id_to_focus,
|
pane_id_to_focus,
|
||||||
client_id,
|
client_id,
|
||||||
) => {
|
) => {
|
||||||
let mut rlock = session_data.write().unwrap();
|
let mut rlock = session_data.write().unwrap();
|
||||||
let session_data = rlock.as_mut().unwrap();
|
let session_data = rlock.as_mut().unwrap();
|
||||||
session_data.set_client_keybinds(client_id, attrs.keybinds.clone());
|
|
||||||
|
let mut runtime_configuration = config.clone();
|
||||||
|
runtime_configuration.options = runtime_config_options.clone();
|
||||||
|
session_data
|
||||||
|
.session_configuration
|
||||||
|
.set_client_saved_configuration(client_id, config.clone());
|
||||||
|
session_data
|
||||||
|
.session_configuration
|
||||||
|
.set_client_runtime_configuration(client_id, runtime_configuration);
|
||||||
|
|
||||||
|
let default_input_mode = config.options.default_mode.unwrap_or_default();
|
||||||
|
session_data
|
||||||
|
.current_input_modes
|
||||||
|
.insert(client_id, default_input_mode);
|
||||||
|
|
||||||
session_state
|
session_state
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|
@ -565,15 +649,14 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||||
.senders
|
.senders
|
||||||
.send_to_plugin(PluginInstruction::AddClient(client_id))
|
.send_to_plugin(PluginInstruction::AddClient(client_id))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let default_mode = options.default_mode.unwrap_or_default();
|
let default_mode = config.options.default_mode.unwrap_or_default();
|
||||||
let mode_info = get_mode_info(
|
let mode_info = get_mode_info(
|
||||||
default_mode,
|
default_mode,
|
||||||
&attrs,
|
&attrs,
|
||||||
session_data.capabilities,
|
session_data.capabilities,
|
||||||
session_data
|
&session_data
|
||||||
.client_keybinds
|
.session_configuration
|
||||||
.get(&client_id)
|
.get_client_keybinds(&client_id),
|
||||||
.unwrap_or(&session_data.client_attributes.keybinds),
|
|
||||||
Some(default_mode),
|
Some(default_mode),
|
||||||
);
|
);
|
||||||
session_data
|
session_data
|
||||||
|
|
@ -853,7 +936,11 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||||
.read()
|
.read()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|c| c.config_options.layout_dir.clone())
|
.unwrap()
|
||||||
|
.session_configuration
|
||||||
|
.get_client_configuration(&client_id)
|
||||||
|
.options
|
||||||
|
.layout_dir
|
||||||
.or_else(|| default_layout_dir());
|
.or_else(|| default_layout_dir());
|
||||||
if let Some(layout_dir) = layout_dir {
|
if let Some(layout_dir) = layout_dir {
|
||||||
connect_to_session.apply_layout_dir(&layout_dir);
|
connect_to_session.apply_layout_dir(&layout_dir);
|
||||||
|
|
@ -904,7 +991,7 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.client_input_modes
|
.current_input_modes
|
||||||
.insert(client_id, input_mode);
|
.insert(client_id, input_mode);
|
||||||
},
|
},
|
||||||
ServerInstruction::ChangeModeForAllClients(input_mode) => {
|
ServerInstruction::ChangeModeForAllClients(input_mode) => {
|
||||||
|
|
@ -915,56 +1002,77 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.change_mode_for_all_clients(input_mode);
|
.change_mode_for_all_clients(input_mode);
|
||||||
},
|
},
|
||||||
ServerInstruction::Reconfigure(client_id, new_config) => {
|
ServerInstruction::Reconfigure {
|
||||||
let mut new_default_mode = None;
|
client_id,
|
||||||
match Options::from_string(&new_config) {
|
config,
|
||||||
Ok(mut new_config_options) => {
|
write_config_to_disk,
|
||||||
if let Some(default_mode) = new_config_options.default_mode.take() {
|
} => {
|
||||||
new_default_mode = Some(default_mode);
|
let (new_config, runtime_config_changed) = session_data
|
||||||
session_data
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.as_mut()
|
|
||||||
.unwrap()
|
|
||||||
.default_mode
|
|
||||||
.insert(client_id, default_mode);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
log::error!("Failed to parse config: {}", e);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
let new_keybinds = session_data
|
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_mut()
|
.as_mut()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.rebind_keys(client_id, new_config)
|
.session_configuration
|
||||||
.clone();
|
.reconfigure_runtime_config(&client_id, config);
|
||||||
|
|
||||||
|
if let Some(new_config) = new_config {
|
||||||
|
if write_config_to_disk {
|
||||||
|
let clear_defaults = true;
|
||||||
|
send_to_client!(
|
||||||
|
client_id,
|
||||||
|
os_input,
|
||||||
|
ServerToClientMsg::WriteConfigToDisk {
|
||||||
|
config: new_config.to_string(clear_defaults)
|
||||||
|
},
|
||||||
|
session_state
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if runtime_config_changed {
|
||||||
|
session_data
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.senders
|
||||||
|
.send_to_screen(ScreenInstruction::Reconfigure {
|
||||||
|
client_id,
|
||||||
|
keybinds: Some(new_config.keybinds.clone()),
|
||||||
|
default_mode: new_config.options.default_mode,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
session_data
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.senders
|
||||||
|
.send_to_plugin(PluginInstruction::Reconfigure {
|
||||||
|
client_id,
|
||||||
|
keybinds: Some(new_config.keybinds),
|
||||||
|
default_mode: new_config.options.default_mode,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ServerInstruction::ConfigWrittenToDisk(client_id, new_config) => {
|
||||||
|
session_data
|
||||||
|
.write()
|
||||||
|
.unwrap()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.session_configuration
|
||||||
|
.new_saved_config(client_id, new_config);
|
||||||
|
},
|
||||||
|
ServerInstruction::FailedToWriteConfigToDisk(client_id, file_path) => {
|
||||||
session_data
|
session_data
|
||||||
.write()
|
.write()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.senders
|
.senders
|
||||||
.send_to_screen(ScreenInstruction::Reconfigure {
|
.send_to_plugin(PluginInstruction::FailedToWriteConfigToDisk { file_path })
|
||||||
client_id,
|
|
||||||
keybinds: new_keybinds.clone(),
|
|
||||||
default_mode: new_default_mode,
|
|
||||||
})
|
|
||||||
.unwrap();
|
|
||||||
session_data
|
|
||||||
.write()
|
|
||||||
.unwrap()
|
|
||||||
.as_ref()
|
|
||||||
.unwrap()
|
|
||||||
.senders
|
|
||||||
.send_to_plugin(PluginInstruction::Reconfigure {
|
|
||||||
client_id,
|
|
||||||
keybinds: new_keybinds,
|
|
||||||
default_mode: new_default_mode,
|
|
||||||
})
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -987,6 +1095,7 @@ fn init_session(
|
||||||
to_server: SenderWithContext<ServerInstruction>,
|
to_server: SenderWithContext<ServerInstruction>,
|
||||||
client_attributes: ClientAttributes,
|
client_attributes: ClientAttributes,
|
||||||
options: SessionOptions,
|
options: SessionOptions,
|
||||||
|
mut config: Config,
|
||||||
plugin_aliases: Box<PluginAliases>,
|
plugin_aliases: Box<PluginAliases>,
|
||||||
) -> SessionMetaData {
|
) -> SessionMetaData {
|
||||||
let SessionOptions {
|
let SessionOptions {
|
||||||
|
|
@ -994,6 +1103,7 @@ fn init_session(
|
||||||
config_options,
|
config_options,
|
||||||
layout,
|
layout,
|
||||||
} = options;
|
} = options;
|
||||||
|
config.options = config.options.merge(*config_options.clone());
|
||||||
|
|
||||||
let _ = SCROLL_BUFFER_SIZE.set(
|
let _ = SCROLL_BUFFER_SIZE.set(
|
||||||
config_options
|
config_options
|
||||||
|
|
@ -1043,6 +1153,7 @@ fn init_session(
|
||||||
.unwrap_or_else(|| get_default_shell());
|
.unwrap_or_else(|| get_default_shell());
|
||||||
|
|
||||||
let default_mode = config_options.default_mode.unwrap_or_default();
|
let default_mode = config_options.default_mode.unwrap_or_default();
|
||||||
|
let default_keybinds = config.keybinds.clone();
|
||||||
|
|
||||||
let pty_thread = thread::Builder::new()
|
let pty_thread = thread::Builder::new()
|
||||||
.name("pty".to_string())
|
.name("pty".to_string())
|
||||||
|
|
@ -1085,13 +1196,12 @@ fn init_session(
|
||||||
let client_attributes_clone = client_attributes.clone();
|
let client_attributes_clone = client_attributes.clone();
|
||||||
let debug = opts.debug;
|
let debug = opts.debug;
|
||||||
let layout = layout.clone();
|
let layout = layout.clone();
|
||||||
let config_options = config_options.clone();
|
|
||||||
move || {
|
move || {
|
||||||
screen_thread_main(
|
screen_thread_main(
|
||||||
screen_bus,
|
screen_bus,
|
||||||
max_panes,
|
max_panes,
|
||||||
client_attributes_clone,
|
client_attributes_clone,
|
||||||
config_options,
|
config,
|
||||||
debug,
|
debug,
|
||||||
layout,
|
layout,
|
||||||
)
|
)
|
||||||
|
|
@ -1135,6 +1245,7 @@ fn init_session(
|
||||||
default_shell,
|
default_shell,
|
||||||
plugin_aliases,
|
plugin_aliases,
|
||||||
default_mode,
|
default_mode,
|
||||||
|
default_keybinds,
|
||||||
)
|
)
|
||||||
.fatal()
|
.fatal()
|
||||||
}
|
}
|
||||||
|
|
@ -1196,26 +1307,35 @@ fn init_session(
|
||||||
default_shell,
|
default_shell,
|
||||||
client_attributes,
|
client_attributes,
|
||||||
layout,
|
layout,
|
||||||
config_options: config_options.clone(),
|
session_configuration: Default::default(),
|
||||||
client_keybinds: HashMap::new(),
|
current_input_modes: HashMap::new(),
|
||||||
client_input_modes: HashMap::new(),
|
|
||||||
screen_thread: Some(screen_thread),
|
screen_thread: Some(screen_thread),
|
||||||
pty_thread: Some(pty_thread),
|
pty_thread: Some(pty_thread),
|
||||||
plugin_thread: Some(plugin_thread),
|
plugin_thread: Some(plugin_thread),
|
||||||
pty_writer_thread: Some(pty_writer_thread),
|
pty_writer_thread: Some(pty_writer_thread),
|
||||||
background_jobs_thread: Some(background_jobs_thread),
|
background_jobs_thread: Some(background_jobs_thread),
|
||||||
default_mode: HashMap::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn setup_wizard_floating_pane() -> FloatingPaneLayout {
|
||||||
|
let mut setup_wizard_pane = FloatingPaneLayout::new();
|
||||||
|
let configuration = BTreeMap::from_iter([("is_setup_wizard".to_owned(), "true".to_owned())]);
|
||||||
|
setup_wizard_pane.run = Some(Run::Plugin(RunPluginOrAlias::Alias(PluginAlias::new(
|
||||||
|
"configuration",
|
||||||
|
&Some(configuration),
|
||||||
|
None,
|
||||||
|
))));
|
||||||
|
setup_wizard_pane
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "singlepass"))]
|
#[cfg(not(feature = "singlepass"))]
|
||||||
fn get_engine() -> Engine {
|
fn get_engine() -> Engine {
|
||||||
log::info!("Compiling plugins using Cranelift");
|
log::info!("Compiling plugins using Cranelift");
|
||||||
Engine::new(Config::new().strategy(Strategy::Cranelift)).unwrap()
|
Engine::new(WasmtimeConfig::new().strategy(Strategy::Cranelift)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "singlepass")]
|
#[cfg(feature = "singlepass")]
|
||||||
fn get_engine() -> Engine {
|
fn get_engine() -> Engine {
|
||||||
log::info!("Compiling plugins using Singlepass");
|
log::info!("Compiling plugins using Singlepass");
|
||||||
Engine::new(Config::new().strategy(Strategy::Winch)).unwrap()
|
Engine::new(WasmtimeConfig::new().strategy(Strategy::Winch)).unwrap()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,9 @@ pub enum PluginInstruction {
|
||||||
keybinds: Option<Keybinds>,
|
keybinds: Option<Keybinds>,
|
||||||
default_mode: Option<InputMode>,
|
default_mode: Option<InputMode>,
|
||||||
},
|
},
|
||||||
|
FailedToWriteConfigToDisk {
|
||||||
|
file_path: Option<PathBuf>,
|
||||||
|
},
|
||||||
WatchFilesystem,
|
WatchFilesystem,
|
||||||
Exit,
|
Exit,
|
||||||
}
|
}
|
||||||
|
|
@ -189,6 +192,9 @@ impl From<&PluginInstruction> for PluginContext {
|
||||||
PluginInstruction::KeybindPipe { .. } => PluginContext::KeybindPipe,
|
PluginInstruction::KeybindPipe { .. } => PluginContext::KeybindPipe,
|
||||||
PluginInstruction::DumpLayoutToPlugin(..) => PluginContext::DumpLayoutToPlugin,
|
PluginInstruction::DumpLayoutToPlugin(..) => PluginContext::DumpLayoutToPlugin,
|
||||||
PluginInstruction::Reconfigure { .. } => PluginContext::Reconfigure,
|
PluginInstruction::Reconfigure { .. } => PluginContext::Reconfigure,
|
||||||
|
PluginInstruction::FailedToWriteConfigToDisk { .. } => {
|
||||||
|
PluginContext::FailedToWriteConfigToDisk
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -206,6 +212,7 @@ pub(crate) fn plugin_thread_main(
|
||||||
default_shell: Option<TerminalAction>,
|
default_shell: Option<TerminalAction>,
|
||||||
plugin_aliases: Box<PluginAliases>,
|
plugin_aliases: Box<PluginAliases>,
|
||||||
default_mode: InputMode,
|
default_mode: InputMode,
|
||||||
|
default_keybinds: Keybinds,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
info!("Wasm main thread starts");
|
info!("Wasm main thread starts");
|
||||||
let plugin_dir = data_dir.join("plugins/");
|
let plugin_dir = data_dir.join("plugins/");
|
||||||
|
|
@ -228,6 +235,7 @@ pub(crate) fn plugin_thread_main(
|
||||||
layout.clone(),
|
layout.clone(),
|
||||||
layout_dir,
|
layout_dir,
|
||||||
default_mode,
|
default_mode,
|
||||||
|
default_keybinds,
|
||||||
);
|
);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
|
@ -764,6 +772,16 @@ pub(crate) fn plugin_thread_main(
|
||||||
.reconfigure(client_id, keybinds, default_mode)
|
.reconfigure(client_id, keybinds, default_mode)
|
||||||
.non_fatal();
|
.non_fatal();
|
||||||
},
|
},
|
||||||
|
PluginInstruction::FailedToWriteConfigToDisk { file_path } => {
|
||||||
|
let updates = vec![(
|
||||||
|
None,
|
||||||
|
None,
|
||||||
|
Event::FailedToWriteConfigToDisk(file_path.map(|f| f.display().to_string())),
|
||||||
|
)];
|
||||||
|
wasm_bridge
|
||||||
|
.update_plugins(updates, shutdown_send.clone())
|
||||||
|
.non_fatal();
|
||||||
|
},
|
||||||
PluginInstruction::WatchFilesystem => {
|
PluginInstruction::WatchFilesystem => {
|
||||||
wasm_bridge.start_fs_watcher_if_not_started();
|
wasm_bridge.start_fs_watcher_if_not_started();
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ pub struct PluginLoader<'a> {
|
||||||
default_layout: Box<Layout>,
|
default_layout: Box<Layout>,
|
||||||
layout_dir: Option<PathBuf>,
|
layout_dir: Option<PathBuf>,
|
||||||
default_mode: InputMode,
|
default_mode: InputMode,
|
||||||
keybinds: Option<Keybinds>,
|
keybinds: Keybinds,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PluginLoader<'a> {
|
impl<'a> PluginLoader<'a> {
|
||||||
|
|
@ -90,7 +90,7 @@ impl<'a> PluginLoader<'a> {
|
||||||
default_shell: Option<TerminalAction>,
|
default_shell: Option<TerminalAction>,
|
||||||
default_layout: Box<Layout>,
|
default_layout: Box<Layout>,
|
||||||
layout_dir: Option<PathBuf>,
|
layout_dir: Option<PathBuf>,
|
||||||
default_mode: InputMode,
|
base_modes: &HashMap<ClientId, InputMode>,
|
||||||
keybinds: &HashMap<ClientId, Keybinds>,
|
keybinds: &HashMap<ClientId, Keybinds>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let err_context = || format!("failed to reload plugin {plugin_id} from memory");
|
let err_context = || format!("failed to reload plugin {plugin_id} from memory");
|
||||||
|
|
@ -100,7 +100,11 @@ impl<'a> PluginLoader<'a> {
|
||||||
return Err(anyhow!("No connected clients, cannot reload plugin"));
|
return Err(anyhow!("No connected clients, cannot reload plugin"));
|
||||||
}
|
}
|
||||||
let first_client_id = connected_clients.remove(0);
|
let first_client_id = connected_clients.remove(0);
|
||||||
let keybinds = keybinds.get(&first_client_id).cloned();
|
let keybinds = keybinds.get(&first_client_id).cloned().unwrap_or_default();
|
||||||
|
let default_mode = base_modes
|
||||||
|
.get(&first_client_id)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
let mut plugin_loader = PluginLoader::new_from_existing_plugin_attributes(
|
let mut plugin_loader = PluginLoader::new_from_existing_plugin_attributes(
|
||||||
&plugin_cache,
|
&plugin_cache,
|
||||||
|
|
@ -157,7 +161,7 @@ impl<'a> PluginLoader<'a> {
|
||||||
skip_cache: bool,
|
skip_cache: bool,
|
||||||
layout_dir: Option<PathBuf>,
|
layout_dir: Option<PathBuf>,
|
||||||
default_mode: InputMode,
|
default_mode: InputMode,
|
||||||
keybinds: Option<Keybinds>,
|
keybinds: Keybinds,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let err_context = || format!("failed to start plugin {plugin_id} for client {client_id}");
|
let err_context = || format!("failed to start plugin {plugin_id} for client {client_id}");
|
||||||
let mut plugin_loader = PluginLoader::new(
|
let mut plugin_loader = PluginLoader::new(
|
||||||
|
|
@ -233,7 +237,7 @@ impl<'a> PluginLoader<'a> {
|
||||||
default_layout: Box<Layout>,
|
default_layout: Box<Layout>,
|
||||||
layout_dir: Option<PathBuf>,
|
layout_dir: Option<PathBuf>,
|
||||||
default_mode: InputMode,
|
default_mode: InputMode,
|
||||||
keybinds: Option<Keybinds>,
|
keybinds: Keybinds,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let mut new_plugins = HashSet::new();
|
let mut new_plugins = HashSet::new();
|
||||||
for plugin_id in plugin_map.lock().unwrap().plugin_ids() {
|
for plugin_id in plugin_map.lock().unwrap().plugin_ids() {
|
||||||
|
|
@ -286,7 +290,7 @@ impl<'a> PluginLoader<'a> {
|
||||||
default_shell: Option<TerminalAction>,
|
default_shell: Option<TerminalAction>,
|
||||||
default_layout: Box<Layout>,
|
default_layout: Box<Layout>,
|
||||||
layout_dir: Option<PathBuf>,
|
layout_dir: Option<PathBuf>,
|
||||||
default_mode: InputMode,
|
base_modes: &HashMap<ClientId, InputMode>,
|
||||||
keybinds: &HashMap<ClientId, Keybinds>,
|
keybinds: &HashMap<ClientId, Keybinds>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let err_context = || format!("failed to reload plugin id {plugin_id}");
|
let err_context = || format!("failed to reload plugin id {plugin_id}");
|
||||||
|
|
@ -297,7 +301,11 @@ impl<'a> PluginLoader<'a> {
|
||||||
return Err(anyhow!("No connected clients, cannot reload plugin"));
|
return Err(anyhow!("No connected clients, cannot reload plugin"));
|
||||||
}
|
}
|
||||||
let first_client_id = connected_clients.remove(0);
|
let first_client_id = connected_clients.remove(0);
|
||||||
let keybinds = keybinds.get(&first_client_id).cloned();
|
let keybinds = keybinds.get(&first_client_id).cloned().unwrap_or_default();
|
||||||
|
let default_mode = base_modes
|
||||||
|
.get(&first_client_id)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
let mut plugin_loader = PluginLoader::new_from_existing_plugin_attributes(
|
let mut plugin_loader = PluginLoader::new_from_existing_plugin_attributes(
|
||||||
&plugin_cache,
|
&plugin_cache,
|
||||||
|
|
@ -350,7 +358,7 @@ impl<'a> PluginLoader<'a> {
|
||||||
default_layout: Box<Layout>,
|
default_layout: Box<Layout>,
|
||||||
layout_dir: Option<PathBuf>,
|
layout_dir: Option<PathBuf>,
|
||||||
default_mode: InputMode,
|
default_mode: InputMode,
|
||||||
keybinds: Option<Keybinds>,
|
keybinds: Keybinds,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let plugin_own_data_dir = ZELLIJ_SESSION_CACHE_DIR
|
let plugin_own_data_dir = ZELLIJ_SESSION_CACHE_DIR
|
||||||
.join(Url::from(&plugin.location).to_string())
|
.join(Url::from(&plugin.location).to_string())
|
||||||
|
|
@ -399,7 +407,7 @@ impl<'a> PluginLoader<'a> {
|
||||||
default_layout: Box<Layout>,
|
default_layout: Box<Layout>,
|
||||||
layout_dir: Option<PathBuf>,
|
layout_dir: Option<PathBuf>,
|
||||||
default_mode: InputMode,
|
default_mode: InputMode,
|
||||||
keybinds: Option<Keybinds>,
|
keybinds: Keybinds,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let err_context = || "Failed to find existing plugin";
|
let err_context = || "Failed to find existing plugin";
|
||||||
let (running_plugin, _subscriptions, _workers) = {
|
let (running_plugin, _subscriptions, _workers) = {
|
||||||
|
|
@ -455,7 +463,7 @@ impl<'a> PluginLoader<'a> {
|
||||||
default_layout: Box<Layout>,
|
default_layout: Box<Layout>,
|
||||||
layout_dir: Option<PathBuf>,
|
layout_dir: Option<PathBuf>,
|
||||||
default_mode: InputMode,
|
default_mode: InputMode,
|
||||||
keybinds: Option<Keybinds>,
|
keybinds: Keybinds,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let err_context = || "Failed to find existing plugin";
|
let err_context = || "Failed to find existing plugin";
|
||||||
let running_plugin = {
|
let running_plugin = {
|
||||||
|
|
@ -851,11 +859,7 @@ impl<'a> PluginLoader<'a> {
|
||||||
layout_dir: self.layout_dir.clone(),
|
layout_dir: self.layout_dir.clone(),
|
||||||
default_mode: self.default_mode.clone(),
|
default_mode: self.default_mode.clone(),
|
||||||
subscriptions: Arc::new(Mutex::new(HashSet::new())),
|
subscriptions: Arc::new(Mutex::new(HashSet::new())),
|
||||||
keybinds: self
|
keybinds: self.keybinds.clone(),
|
||||||
.keybinds
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or_else(|| &self.client_attributes.keybinds)
|
|
||||||
.clone(),
|
|
||||||
stdin_pipe,
|
stdin_pipe,
|
||||||
stdout_pipe,
|
stdout_pipe,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ use zellij_utils::data::{
|
||||||
PluginCapabilities,
|
PluginCapabilities,
|
||||||
};
|
};
|
||||||
use zellij_utils::errors::ErrorContext;
|
use zellij_utils::errors::ErrorContext;
|
||||||
|
use zellij_utils::input::keybinds::Keybinds;
|
||||||
use zellij_utils::input::layout::{
|
use zellij_utils::input::layout::{
|
||||||
Layout, PluginAlias, PluginUserConfiguration, RunPlugin, RunPluginLocation, RunPluginOrAlias,
|
Layout, PluginAlias, PluginUserConfiguration, RunPlugin, RunPluginLocation, RunPluginOrAlias,
|
||||||
};
|
};
|
||||||
|
|
@ -58,6 +59,35 @@ macro_rules! log_actions_in_thread {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
macro_rules! log_actions_in_thread_struct {
|
||||||
|
( $arc_mutex_log:expr, $exit_event:path, $receiver:expr, $exit_after_count:expr ) => {
|
||||||
|
std::thread::Builder::new()
|
||||||
|
.name("logger thread".to_string())
|
||||||
|
.spawn({
|
||||||
|
let log = $arc_mutex_log.clone();
|
||||||
|
let mut exit_event_count = 0;
|
||||||
|
move || loop {
|
||||||
|
let (event, _err_ctx) = $receiver
|
||||||
|
.recv()
|
||||||
|
.expect("failed to receive event on channel");
|
||||||
|
match event {
|
||||||
|
$exit_event { .. } => {
|
||||||
|
exit_event_count += 1;
|
||||||
|
log.lock().unwrap().push(event);
|
||||||
|
if exit_event_count == $exit_after_count {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
log.lock().unwrap().push(event);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! grant_permissions_and_log_actions_in_thread {
|
macro_rules! grant_permissions_and_log_actions_in_thread {
|
||||||
( $arc_mutex_log:expr, $exit_event:path, $receiver:expr, $exit_after_count:expr, $permission_type:expr, $cache_path:expr, $plugin_thread_sender:expr, $client_id:expr ) => {
|
( $arc_mutex_log:expr, $exit_event:path, $receiver:expr, $exit_after_count:expr, $permission_type:expr, $cache_path:expr, $plugin_thread_sender:expr, $client_id:expr ) => {
|
||||||
std::thread::Builder::new()
|
std::thread::Builder::new()
|
||||||
|
|
@ -282,6 +312,7 @@ fn create_plugin_thread(
|
||||||
default_shell_action,
|
default_shell_action,
|
||||||
Box::new(plugin_aliases),
|
Box::new(plugin_aliases),
|
||||||
InputMode::Normal,
|
InputMode::Normal,
|
||||||
|
Keybinds::default(),
|
||||||
)
|
)
|
||||||
.expect("TEST")
|
.expect("TEST")
|
||||||
})
|
})
|
||||||
|
|
@ -362,6 +393,7 @@ fn create_plugin_thread_with_server_receiver(
|
||||||
default_shell_action,
|
default_shell_action,
|
||||||
Box::new(PluginAliases::default()),
|
Box::new(PluginAliases::default()),
|
||||||
InputMode::Normal,
|
InputMode::Normal,
|
||||||
|
Keybinds::default(),
|
||||||
)
|
)
|
||||||
.expect("TEST");
|
.expect("TEST");
|
||||||
})
|
})
|
||||||
|
|
@ -448,6 +480,7 @@ fn create_plugin_thread_with_pty_receiver(
|
||||||
default_shell_action,
|
default_shell_action,
|
||||||
Box::new(PluginAliases::default()),
|
Box::new(PluginAliases::default()),
|
||||||
InputMode::Normal,
|
InputMode::Normal,
|
||||||
|
Keybinds::default(),
|
||||||
)
|
)
|
||||||
.expect("TEST")
|
.expect("TEST")
|
||||||
})
|
})
|
||||||
|
|
@ -529,6 +562,7 @@ fn create_plugin_thread_with_background_jobs_receiver(
|
||||||
default_shell_action,
|
default_shell_action,
|
||||||
Box::new(PluginAliases::default()),
|
Box::new(PluginAliases::default()),
|
||||||
InputMode::Normal,
|
InputMode::Normal,
|
||||||
|
Keybinds::default(),
|
||||||
)
|
)
|
||||||
.expect("TEST")
|
.expect("TEST")
|
||||||
})
|
})
|
||||||
|
|
@ -6525,7 +6559,7 @@ pub fn reconfigure_plugin_command() {
|
||||||
client_id
|
client_id
|
||||||
);
|
);
|
||||||
let received_server_instruction = Arc::new(Mutex::new(vec![]));
|
let received_server_instruction = Arc::new(Mutex::new(vec![]));
|
||||||
let server_thread = log_actions_in_thread!(
|
let server_thread = log_actions_in_thread_struct!(
|
||||||
received_server_instruction,
|
received_server_instruction,
|
||||||
ServerInstruction::Reconfigure,
|
ServerInstruction::Reconfigure,
|
||||||
server_receiver,
|
server_receiver,
|
||||||
|
|
@ -6561,7 +6595,7 @@ pub fn reconfigure_plugin_command() {
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.find_map(|i| {
|
.find_map(|i| {
|
||||||
if let ServerInstruction::Reconfigure(..) = i {
|
if let ServerInstruction::Reconfigure { .. } = i {
|
||||||
Some(i.clone())
|
Some(i.clone())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
---
|
---
|
||||||
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
||||||
assertion_line: 6571
|
assertion_line: 6605
|
||||||
expression: "format!(\"{:#?}\", reconfigure_event)"
|
expression: "format!(\"{:#?}\", reconfigure_event)"
|
||||||
---
|
---
|
||||||
Some(
|
Some(
|
||||||
Reconfigure(
|
Reconfigure {
|
||||||
1,
|
client_id: 1,
|
||||||
"\n keybinds {\n locked {\n bind \"a\" { NewTab; }\n }\n }\n ",
|
config: "\n keybinds {\n locked {\n bind \"a\" { NewTab; }\n }\n }\n ",
|
||||||
),
|
write_config_to_disk: true,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -104,7 +104,9 @@ pub struct WasmBridge {
|
||||||
pending_pipes: PendingPipes,
|
pending_pipes: PendingPipes,
|
||||||
layout_dir: Option<PathBuf>,
|
layout_dir: Option<PathBuf>,
|
||||||
default_mode: InputMode,
|
default_mode: InputMode,
|
||||||
|
default_keybinds: Keybinds,
|
||||||
keybinds: HashMap<ClientId, Keybinds>,
|
keybinds: HashMap<ClientId, Keybinds>,
|
||||||
|
base_modes: HashMap<ClientId, InputMode>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WasmBridge {
|
impl WasmBridge {
|
||||||
|
|
@ -120,6 +122,7 @@ impl WasmBridge {
|
||||||
default_layout: Box<Layout>,
|
default_layout: Box<Layout>,
|
||||||
layout_dir: Option<PathBuf>,
|
layout_dir: Option<PathBuf>,
|
||||||
default_mode: InputMode,
|
default_mode: InputMode,
|
||||||
|
default_keybinds: Keybinds,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let plugin_map = Arc::new(Mutex::new(PluginMap::default()));
|
let plugin_map = Arc::new(Mutex::new(PluginMap::default()));
|
||||||
let connected_clients: Arc<Mutex<Vec<ClientId>>> = Arc::new(Mutex::new(vec![]));
|
let connected_clients: Arc<Mutex<Vec<ClientId>>> = Arc::new(Mutex::new(vec![]));
|
||||||
|
|
@ -151,7 +154,9 @@ impl WasmBridge {
|
||||||
pending_pipes: Default::default(),
|
pending_pipes: Default::default(),
|
||||||
layout_dir,
|
layout_dir,
|
||||||
default_mode,
|
default_mode,
|
||||||
|
default_keybinds,
|
||||||
keybinds: HashMap::new(),
|
keybinds: HashMap::new(),
|
||||||
|
base_modes: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn load_plugin(
|
pub fn load_plugin(
|
||||||
|
|
@ -208,8 +213,16 @@ impl WasmBridge {
|
||||||
let default_shell = self.default_shell.clone();
|
let default_shell = self.default_shell.clone();
|
||||||
let default_layout = self.default_layout.clone();
|
let default_layout = self.default_layout.clone();
|
||||||
let layout_dir = self.layout_dir.clone();
|
let layout_dir = self.layout_dir.clone();
|
||||||
let default_mode = self.default_mode;
|
let default_mode = self
|
||||||
let keybinds = self.keybinds.get(&client_id).cloned();
|
.base_modes
|
||||||
|
.get(&client_id)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(self.default_mode);
|
||||||
|
let keybinds = self
|
||||||
|
.keybinds
|
||||||
|
.get(&client_id)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| self.default_keybinds.clone());
|
||||||
async move {
|
async move {
|
||||||
let _ = senders.send_to_background_jobs(
|
let _ = senders.send_to_background_jobs(
|
||||||
BackgroundJob::AnimatePluginLoading(plugin_id),
|
BackgroundJob::AnimatePluginLoading(plugin_id),
|
||||||
|
|
@ -350,7 +363,7 @@ impl WasmBridge {
|
||||||
let default_shell = self.default_shell.clone();
|
let default_shell = self.default_shell.clone();
|
||||||
let default_layout = self.default_layout.clone();
|
let default_layout = self.default_layout.clone();
|
||||||
let layout_dir = self.layout_dir.clone();
|
let layout_dir = self.layout_dir.clone();
|
||||||
let default_mode = self.default_mode;
|
let base_modes = self.base_modes.clone();
|
||||||
let keybinds = self.keybinds.clone();
|
let keybinds = self.keybinds.clone();
|
||||||
async move {
|
async move {
|
||||||
match PluginLoader::reload_plugin(
|
match PluginLoader::reload_plugin(
|
||||||
|
|
@ -369,7 +382,7 @@ impl WasmBridge {
|
||||||
default_shell.clone(),
|
default_shell.clone(),
|
||||||
default_layout.clone(),
|
default_layout.clone(),
|
||||||
layout_dir.clone(),
|
layout_dir.clone(),
|
||||||
default_mode,
|
&base_modes,
|
||||||
&keybinds,
|
&keybinds,
|
||||||
) {
|
) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
|
|
@ -396,7 +409,7 @@ impl WasmBridge {
|
||||||
default_shell.clone(),
|
default_shell.clone(),
|
||||||
default_layout.clone(),
|
default_layout.clone(),
|
||||||
layout_dir.clone(),
|
layout_dir.clone(),
|
||||||
default_mode,
|
&base_modes,
|
||||||
&keybinds,
|
&keybinds,
|
||||||
) {
|
) {
|
||||||
Ok(_) => handle_plugin_successful_loading(&senders, *plugin_id),
|
Ok(_) => handle_plugin_successful_loading(&senders, *plugin_id),
|
||||||
|
|
@ -451,7 +464,10 @@ impl WasmBridge {
|
||||||
self.default_layout.clone(),
|
self.default_layout.clone(),
|
||||||
self.layout_dir.clone(),
|
self.layout_dir.clone(),
|
||||||
self.default_mode,
|
self.default_mode,
|
||||||
self.keybinds.get(&client_id).cloned(),
|
self.keybinds
|
||||||
|
.get(&client_id)
|
||||||
|
.cloned()
|
||||||
|
.unwrap_or_else(|| self.default_keybinds.clone()),
|
||||||
) {
|
) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
let _ = self
|
let _ = self
|
||||||
|
|
@ -827,7 +843,7 @@ impl WasmBridge {
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
if let Some(default_mode) = default_mode.as_ref() {
|
if let Some(default_mode) = default_mode.as_ref() {
|
||||||
self.default_mode = *default_mode;
|
self.base_modes.insert(client_id, *default_mode);
|
||||||
}
|
}
|
||||||
if let Some(keybinds) = keybinds.as_ref() {
|
if let Some(keybinds) = keybinds.as_ref() {
|
||||||
self.keybinds.insert(client_id, keybinds.clone());
|
self.keybinds.insert(client_id, keybinds.clone());
|
||||||
|
|
@ -1332,6 +1348,7 @@ fn check_event_permission(
|
||||||
| Event::PaneClosed(..)
|
| Event::PaneClosed(..)
|
||||||
| Event::EditPaneOpened(..)
|
| Event::EditPaneOpened(..)
|
||||||
| Event::EditPaneExited(..)
|
| Event::EditPaneExited(..)
|
||||||
|
| Event::FailedToWriteConfigToDisk(..)
|
||||||
| Event::CommandPaneReRun(..)
|
| Event::CommandPaneReRun(..)
|
||||||
| Event::InputReceived => PermissionType::ReadApplicationState,
|
| Event::InputReceived => PermissionType::ReadApplicationState,
|
||||||
_ => return (PermissionStatus::Granted, None),
|
_ => return (PermissionStatus::Granted, None),
|
||||||
|
|
|
||||||
|
|
@ -257,7 +257,9 @@ fn host_run_plugin_command(caller: Caller<'_, PluginEnv>) {
|
||||||
PluginCommand::WatchFilesystem => watch_filesystem(env),
|
PluginCommand::WatchFilesystem => watch_filesystem(env),
|
||||||
PluginCommand::DumpSessionLayout => dump_session_layout(env),
|
PluginCommand::DumpSessionLayout => dump_session_layout(env),
|
||||||
PluginCommand::CloseSelf => close_self(env),
|
PluginCommand::CloseSelf => close_self(env),
|
||||||
PluginCommand::Reconfigure(new_config) => reconfigure(env, new_config)?,
|
PluginCommand::Reconfigure(new_config, write_config_to_disk) => {
|
||||||
|
reconfigure(env, new_config, write_config_to_disk)?
|
||||||
|
},
|
||||||
PluginCommand::HidePaneWithId(pane_id) => {
|
PluginCommand::HidePaneWithId(pane_id) => {
|
||||||
hide_pane_with_id(env, pane_id.into())?
|
hide_pane_with_id(env, pane_id.into())?
|
||||||
},
|
},
|
||||||
|
|
@ -894,11 +896,15 @@ fn close_self(env: &PluginEnv) {
|
||||||
.non_fatal();
|
.non_fatal();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reconfigure(env: &PluginEnv, new_config: String) -> Result<()> {
|
fn reconfigure(env: &PluginEnv, new_config: String, write_config_to_disk: bool) -> Result<()> {
|
||||||
let err_context = || "Failed to reconfigure";
|
let err_context = || "Failed to reconfigure";
|
||||||
let client_id = env.client_id;
|
let client_id = env.client_id;
|
||||||
env.senders
|
env.senders
|
||||||
.send_to_server(ServerInstruction::Reconfigure(client_id, new_config))
|
.send_to_server(ServerInstruction::Reconfigure {
|
||||||
|
client_id,
|
||||||
|
config: new_config,
|
||||||
|
write_config_to_disk,
|
||||||
|
})
|
||||||
.with_context(err_context)?;
|
.with_context(err_context)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1045,19 +1045,13 @@ pub(crate) fn route_thread_main(
|
||||||
rlocked_sessions.default_shell.clone(),
|
rlocked_sessions.default_shell.clone(),
|
||||||
rlocked_sessions.layout.clone(),
|
rlocked_sessions.layout.clone(),
|
||||||
Some(&mut seen_cli_pipes),
|
Some(&mut seen_cli_pipes),
|
||||||
|
keybinds.clone(),
|
||||||
rlocked_sessions
|
rlocked_sessions
|
||||||
.client_keybinds
|
.session_configuration
|
||||||
.get(&client_id)
|
.get_client_configuration(&client_id)
|
||||||
.unwrap_or(
|
.options
|
||||||
&rlocked_sessions
|
|
||||||
.client_attributes
|
|
||||||
.keybinds,
|
|
||||||
)
|
|
||||||
.clone(),
|
|
||||||
rlocked_sessions
|
|
||||||
.default_mode
|
.default_mode
|
||||||
.get(&client_id)
|
.unwrap_or(InputMode::Normal)
|
||||||
.unwrap_or(&InputMode::Normal)
|
|
||||||
.clone(),
|
.clone(),
|
||||||
)? {
|
)? {
|
||||||
should_break = true;
|
should_break = true;
|
||||||
|
|
@ -1084,14 +1078,15 @@ pub(crate) fn route_thread_main(
|
||||||
rlocked_sessions.layout.clone(),
|
rlocked_sessions.layout.clone(),
|
||||||
Some(&mut seen_cli_pipes),
|
Some(&mut seen_cli_pipes),
|
||||||
rlocked_sessions
|
rlocked_sessions
|
||||||
.client_keybinds
|
.session_configuration
|
||||||
.get(&client_id)
|
.get_client_keybinds(&client_id)
|
||||||
.unwrap_or(&rlocked_sessions.client_attributes.keybinds)
|
|
||||||
.clone(),
|
.clone(),
|
||||||
rlocked_sessions
|
rlocked_sessions
|
||||||
|
.session_configuration
|
||||||
|
.get_client_configuration(&client_id)
|
||||||
|
.options
|
||||||
.default_mode
|
.default_mode
|
||||||
.get(&client_id)
|
.unwrap_or(InputMode::Normal)
|
||||||
.unwrap_or(&InputMode::Normal)
|
|
||||||
.clone(),
|
.clone(),
|
||||||
)? {
|
)? {
|
||||||
should_break = true;
|
should_break = true;
|
||||||
|
|
@ -1164,16 +1159,20 @@ pub(crate) fn route_thread_main(
|
||||||
ClientToServerMsg::NewClient(
|
ClientToServerMsg::NewClient(
|
||||||
client_attributes,
|
client_attributes,
|
||||||
cli_args,
|
cli_args,
|
||||||
opts,
|
config,
|
||||||
|
runtime_config_options,
|
||||||
layout,
|
layout,
|
||||||
plugin_aliases,
|
plugin_aliases,
|
||||||
|
should_launch_setup_wizard,
|
||||||
) => {
|
) => {
|
||||||
let new_client_instruction = ServerInstruction::NewClient(
|
let new_client_instruction = ServerInstruction::NewClient(
|
||||||
client_attributes,
|
client_attributes,
|
||||||
cli_args,
|
cli_args,
|
||||||
opts,
|
config,
|
||||||
|
runtime_config_options,
|
||||||
layout,
|
layout,
|
||||||
plugin_aliases,
|
plugin_aliases,
|
||||||
|
should_launch_setup_wizard,
|
||||||
client_id,
|
client_id,
|
||||||
);
|
);
|
||||||
to_server
|
to_server
|
||||||
|
|
@ -1182,13 +1181,15 @@ pub(crate) fn route_thread_main(
|
||||||
},
|
},
|
||||||
ClientToServerMsg::AttachClient(
|
ClientToServerMsg::AttachClient(
|
||||||
client_attributes,
|
client_attributes,
|
||||||
opts,
|
config,
|
||||||
|
runtime_config_options,
|
||||||
tab_position_to_focus,
|
tab_position_to_focus,
|
||||||
pane_id_to_focus,
|
pane_id_to_focus,
|
||||||
) => {
|
) => {
|
||||||
let attach_client_instruction = ServerInstruction::AttachClient(
|
let attach_client_instruction = ServerInstruction::AttachClient(
|
||||||
client_attributes,
|
client_attributes,
|
||||||
opts,
|
config,
|
||||||
|
runtime_config_options,
|
||||||
tab_position_to_focus,
|
tab_position_to_focus,
|
||||||
pane_id_to_focus,
|
pane_id_to_focus,
|
||||||
client_id,
|
client_id,
|
||||||
|
|
@ -1219,6 +1220,16 @@ pub(crate) fn route_thread_main(
|
||||||
ClientToServerMsg::ListClients => {
|
ClientToServerMsg::ListClients => {
|
||||||
let _ = to_server.send(ServerInstruction::ActiveClients(client_id));
|
let _ = to_server.send(ServerInstruction::ActiveClients(client_id));
|
||||||
},
|
},
|
||||||
|
ClientToServerMsg::ConfigWrittenToDisk(config) => {
|
||||||
|
let _ = to_server
|
||||||
|
.send(ServerInstruction::ConfigWrittenToDisk(client_id, config));
|
||||||
|
},
|
||||||
|
ClientToServerMsg::FailedToWriteConfigToDisk(failed_path) => {
|
||||||
|
let _ = to_server.send(ServerInstruction::FailedToWriteConfigToDisk(
|
||||||
|
client_id,
|
||||||
|
failed_path,
|
||||||
|
));
|
||||||
|
},
|
||||||
}
|
}
|
||||||
Ok(should_break)
|
Ok(should_break)
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ use zellij_utils::data::{
|
||||||
};
|
};
|
||||||
use zellij_utils::errors::prelude::*;
|
use zellij_utils::errors::prelude::*;
|
||||||
use zellij_utils::input::command::RunCommand;
|
use zellij_utils::input::command::RunCommand;
|
||||||
|
use zellij_utils::input::config::Config;
|
||||||
use zellij_utils::input::keybinds::Keybinds;
|
use zellij_utils::input::keybinds::Keybinds;
|
||||||
use zellij_utils::input::options::Clipboard;
|
use zellij_utils::input::options::Clipboard;
|
||||||
use zellij_utils::pane_size::{Size, SizeInPixels};
|
use zellij_utils::pane_size::{Size, SizeInPixels};
|
||||||
|
|
@ -2361,10 +2362,11 @@ pub(crate) fn screen_thread_main(
|
||||||
bus: Bus<ScreenInstruction>,
|
bus: Bus<ScreenInstruction>,
|
||||||
max_panes: Option<usize>,
|
max_panes: Option<usize>,
|
||||||
client_attributes: ClientAttributes,
|
client_attributes: ClientAttributes,
|
||||||
config_options: Box<Options>,
|
config: Config,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
default_layout: Box<Layout>,
|
default_layout: Box<Layout>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
|
let config_options = config.options;
|
||||||
let arrow_fonts = !config_options.simplified_ui.unwrap_or_default();
|
let arrow_fonts = !config_options.simplified_ui.unwrap_or_default();
|
||||||
let draw_pane_frames = config_options.pane_frames.unwrap_or(true);
|
let draw_pane_frames = config_options.pane_frames.unwrap_or(true);
|
||||||
let auto_layout = config_options.auto_layout.unwrap_or(true);
|
let auto_layout = config_options.auto_layout.unwrap_or(true);
|
||||||
|
|
@ -2403,7 +2405,7 @@ pub(crate) fn screen_thread_main(
|
||||||
// ¯\_(ツ)_/¯
|
// ¯\_(ツ)_/¯
|
||||||
arrow_fonts: !arrow_fonts,
|
arrow_fonts: !arrow_fonts,
|
||||||
},
|
},
|
||||||
&client_attributes.keybinds,
|
&config.keybinds,
|
||||||
config_options.default_mode,
|
config_options.default_mode,
|
||||||
),
|
),
|
||||||
draw_pane_frames,
|
draw_pane_frames,
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ use zellij_utils::data::{Event, Resize, Style};
|
||||||
use zellij_utils::errors::{prelude::*, ErrorContext};
|
use zellij_utils::errors::{prelude::*, ErrorContext};
|
||||||
use zellij_utils::input::actions::Action;
|
use zellij_utils::input::actions::Action;
|
||||||
use zellij_utils::input::command::{RunCommand, TerminalAction};
|
use zellij_utils::input::command::{RunCommand, TerminalAction};
|
||||||
|
use zellij_utils::input::config::Config;
|
||||||
use zellij_utils::input::layout::{
|
use zellij_utils::input::layout::{
|
||||||
FloatingPaneLayout, Layout, PluginAlias, PluginUserConfiguration, Run, RunPlugin,
|
FloatingPaneLayout, Layout, PluginAlias, PluginUserConfiguration, Run, RunPlugin,
|
||||||
RunPluginLocation, RunPluginOrAlias, SplitDirection, SplitSize, TiledPaneLayout,
|
RunPluginLocation, RunPluginOrAlias, SplitDirection, SplitSize, TiledPaneLayout,
|
||||||
|
|
@ -114,12 +115,20 @@ fn send_cli_action_to_server(
|
||||||
let get_current_dir = || PathBuf::from(".");
|
let get_current_dir = || PathBuf::from(".");
|
||||||
let actions = Action::actions_from_cli(cli_action, Box::new(get_current_dir), None).unwrap();
|
let actions = Action::actions_from_cli(cli_action, Box::new(get_current_dir), None).unwrap();
|
||||||
let senders = session_metadata.senders.clone();
|
let senders = session_metadata.senders.clone();
|
||||||
let client_keybinds = session_metadata.client_keybinds.clone();
|
|
||||||
let default_mode = session_metadata.default_mode.clone();
|
|
||||||
let capabilities = PluginCapabilities::default();
|
let capabilities = PluginCapabilities::default();
|
||||||
let client_attributes = ClientAttributes::default();
|
let client_attributes = ClientAttributes::default();
|
||||||
let default_shell = None;
|
let default_shell = None;
|
||||||
let default_layout = Box::new(Layout::default());
|
let default_layout = Box::new(Layout::default());
|
||||||
|
let default_mode = session_metadata
|
||||||
|
.session_configuration
|
||||||
|
.get_client_configuration(&client_id)
|
||||||
|
.options
|
||||||
|
.default_mode
|
||||||
|
.unwrap_or(InputMode::Normal);
|
||||||
|
let client_keybinds = session_metadata
|
||||||
|
.session_configuration
|
||||||
|
.get_client_keybinds(&client_id)
|
||||||
|
.clone();
|
||||||
for action in actions {
|
for action in actions {
|
||||||
route_action(
|
route_action(
|
||||||
action,
|
action,
|
||||||
|
|
@ -131,14 +140,8 @@ fn send_cli_action_to_server(
|
||||||
default_shell.clone(),
|
default_shell.clone(),
|
||||||
default_layout.clone(),
|
default_layout.clone(),
|
||||||
None,
|
None,
|
||||||
client_keybinds
|
client_keybinds.clone(),
|
||||||
.get(&client_id)
|
default_mode,
|
||||||
.unwrap_or(&session_metadata.client_attributes.keybinds)
|
|
||||||
.clone(),
|
|
||||||
default_mode
|
|
||||||
.get(&client_id)
|
|
||||||
.unwrap_or(&InputMode::Normal)
|
|
||||||
.clone(),
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
@ -307,6 +310,7 @@ struct MockScreen {
|
||||||
pub client_attributes: ClientAttributes,
|
pub client_attributes: ClientAttributes,
|
||||||
pub config_options: Options,
|
pub config_options: Options,
|
||||||
pub session_metadata: SessionMetaData,
|
pub session_metadata: SessionMetaData,
|
||||||
|
pub config: Config,
|
||||||
last_opened_tab_index: Option<usize>,
|
last_opened_tab_index: Option<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -316,7 +320,7 @@ impl MockScreen {
|
||||||
initial_layout: Option<TiledPaneLayout>,
|
initial_layout: Option<TiledPaneLayout>,
|
||||||
initial_floating_panes_layout: Vec<FloatingPaneLayout>,
|
initial_floating_panes_layout: Vec<FloatingPaneLayout>,
|
||||||
) -> std::thread::JoinHandle<()> {
|
) -> std::thread::JoinHandle<()> {
|
||||||
let config_options = self.config_options.clone();
|
let config = self.config.clone();
|
||||||
let client_attributes = self.client_attributes.clone();
|
let client_attributes = self.client_attributes.clone();
|
||||||
let screen_bus = Bus::new(
|
let screen_bus = Bus::new(
|
||||||
vec![self.screen_receiver.take().unwrap()],
|
vec![self.screen_receiver.take().unwrap()],
|
||||||
|
|
@ -338,7 +342,7 @@ impl MockScreen {
|
||||||
screen_bus,
|
screen_bus,
|
||||||
None,
|
None,
|
||||||
client_attributes,
|
client_attributes,
|
||||||
Box::new(config_options),
|
config,
|
||||||
debug,
|
debug,
|
||||||
Box::new(Layout::default()),
|
Box::new(Layout::default()),
|
||||||
)
|
)
|
||||||
|
|
@ -391,7 +395,7 @@ impl MockScreen {
|
||||||
initial_layout: Option<TiledPaneLayout>,
|
initial_layout: Option<TiledPaneLayout>,
|
||||||
initial_floating_panes_layout: Vec<FloatingPaneLayout>,
|
initial_floating_panes_layout: Vec<FloatingPaneLayout>,
|
||||||
) -> std::thread::JoinHandle<()> {
|
) -> std::thread::JoinHandle<()> {
|
||||||
let config_options = self.config_options.clone();
|
let config = self.config.clone();
|
||||||
let client_attributes = self.client_attributes.clone();
|
let client_attributes = self.client_attributes.clone();
|
||||||
let screen_bus = Bus::new(
|
let screen_bus = Bus::new(
|
||||||
vec![self.screen_receiver.take().unwrap()],
|
vec![self.screen_receiver.take().unwrap()],
|
||||||
|
|
@ -413,7 +417,7 @@ impl MockScreen {
|
||||||
screen_bus,
|
screen_bus,
|
||||||
None,
|
None,
|
||||||
client_attributes,
|
client_attributes,
|
||||||
Box::new(config_options),
|
config,
|
||||||
debug,
|
debug,
|
||||||
Box::new(Layout::default()),
|
Box::new(Layout::default()),
|
||||||
)
|
)
|
||||||
|
|
@ -522,11 +526,9 @@ impl MockScreen {
|
||||||
plugin_thread: None,
|
plugin_thread: None,
|
||||||
pty_writer_thread: None,
|
pty_writer_thread: None,
|
||||||
background_jobs_thread: None,
|
background_jobs_thread: None,
|
||||||
config_options: Default::default(),
|
session_configuration: self.session_metadata.session_configuration.clone(),
|
||||||
layout,
|
layout,
|
||||||
client_input_modes: HashMap::new(),
|
current_input_modes: self.session_metadata.current_input_modes.clone(),
|
||||||
client_keybinds: HashMap::new(),
|
|
||||||
default_mode: self.session_metadata.default_mode.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -582,11 +584,9 @@ impl MockScreen {
|
||||||
plugin_thread: None,
|
plugin_thread: None,
|
||||||
pty_writer_thread: None,
|
pty_writer_thread: None,
|
||||||
background_jobs_thread: None,
|
background_jobs_thread: None,
|
||||||
config_options: Default::default(),
|
|
||||||
layout,
|
layout,
|
||||||
client_input_modes: HashMap::new(),
|
session_configuration: Default::default(),
|
||||||
client_keybinds: HashMap::new(),
|
current_input_modes: HashMap::new(),
|
||||||
default_mode: HashMap::new(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let os_input = FakeInputOutput::default();
|
let os_input = FakeInputOutput::default();
|
||||||
|
|
@ -611,6 +611,7 @@ impl MockScreen {
|
||||||
config_options,
|
config_options,
|
||||||
session_metadata,
|
session_metadata,
|
||||||
last_opened_tab_index: None,
|
last_opened_tab_index: None,
|
||||||
|
config: Config::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -842,8 +842,8 @@ pub fn dump_session_layout() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Rebind keys for the current user
|
/// Rebind keys for the current user
|
||||||
pub fn reconfigure(new_config: String) {
|
pub fn reconfigure(new_config: String, save_configuration_file: bool) {
|
||||||
let plugin_command = PluginCommand::Reconfigure(new_config);
|
let plugin_command = PluginCommand::Reconfigure(new_config, save_configuration_file);
|
||||||
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
|
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
|
||||||
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
|
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
|
||||||
unsafe { host_run_plugin_command() };
|
unsafe { host_run_plugin_command() };
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ pub struct Event {
|
||||||
pub name: i32,
|
pub name: i32,
|
||||||
#[prost(
|
#[prost(
|
||||||
oneof = "event::Payload",
|
oneof = "event::Payload",
|
||||||
tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21"
|
tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22"
|
||||||
)]
|
)]
|
||||||
pub payload: ::core::option::Option<event::Payload>,
|
pub payload: ::core::option::Option<event::Payload>,
|
||||||
}
|
}
|
||||||
|
|
@ -60,10 +60,18 @@ pub mod event {
|
||||||
EditPaneExitedPayload(super::EditPaneExitedPayload),
|
EditPaneExitedPayload(super::EditPaneExitedPayload),
|
||||||
#[prost(message, tag = "21")]
|
#[prost(message, tag = "21")]
|
||||||
CommandPaneRerunPayload(super::CommandPaneReRunPayload),
|
CommandPaneRerunPayload(super::CommandPaneReRunPayload),
|
||||||
|
#[prost(message, tag = "22")]
|
||||||
|
FailedToWriteConfigToDiskPayload(super::FailedToWriteConfigToDiskPayload),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct FailedToWriteConfigToDiskPayload {
|
||||||
|
#[prost(string, optional, tag = "1")]
|
||||||
|
pub file_path: ::core::option::Option<::prost::alloc::string::String>,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct CommandPaneReRunPayload {
|
pub struct CommandPaneReRunPayload {
|
||||||
#[prost(uint32, tag = "1")]
|
#[prost(uint32, tag = "1")]
|
||||||
pub terminal_pane_id: u32,
|
pub terminal_pane_id: u32,
|
||||||
|
|
@ -426,6 +434,7 @@ pub enum EventType {
|
||||||
EditPaneOpened = 22,
|
EditPaneOpened = 22,
|
||||||
EditPaneExited = 23,
|
EditPaneExited = 23,
|
||||||
CommandPaneReRun = 24,
|
CommandPaneReRun = 24,
|
||||||
|
FailedToWriteConfigToDisk = 25,
|
||||||
}
|
}
|
||||||
impl EventType {
|
impl EventType {
|
||||||
/// String value of the enum field names used in the ProtoBuf definition.
|
/// String value of the enum field names used in the ProtoBuf definition.
|
||||||
|
|
@ -459,6 +468,7 @@ impl EventType {
|
||||||
EventType::EditPaneOpened => "EditPaneOpened",
|
EventType::EditPaneOpened => "EditPaneOpened",
|
||||||
EventType::EditPaneExited => "EditPaneExited",
|
EventType::EditPaneExited => "EditPaneExited",
|
||||||
EventType::CommandPaneReRun => "CommandPaneReRun",
|
EventType::CommandPaneReRun => "CommandPaneReRun",
|
||||||
|
EventType::FailedToWriteConfigToDisk => "FailedToWriteConfigToDisk",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||||
|
|
@ -489,6 +499,7 @@ impl EventType {
|
||||||
"EditPaneOpened" => Some(Self::EditPaneOpened),
|
"EditPaneOpened" => Some(Self::EditPaneOpened),
|
||||||
"EditPaneExited" => Some(Self::EditPaneExited),
|
"EditPaneExited" => Some(Self::EditPaneExited),
|
||||||
"CommandPaneReRun" => Some(Self::CommandPaneReRun),
|
"CommandPaneReRun" => Some(Self::CommandPaneReRun),
|
||||||
|
"FailedToWriteConfigToDisk" => Some(Self::FailedToWriteConfigToDisk),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -118,8 +118,8 @@ pub mod plugin_command {
|
||||||
ScanHostFolderPayload(::prost::alloc::string::String),
|
ScanHostFolderPayload(::prost::alloc::string::String),
|
||||||
#[prost(message, tag = "62")]
|
#[prost(message, tag = "62")]
|
||||||
NewTabsWithLayoutInfoPayload(super::NewTabsWithLayoutInfoPayload),
|
NewTabsWithLayoutInfoPayload(super::NewTabsWithLayoutInfoPayload),
|
||||||
#[prost(string, tag = "63")]
|
#[prost(message, tag = "63")]
|
||||||
ReconfigurePayload(::prost::alloc::string::String),
|
ReconfigurePayload(super::ReconfigurePayload),
|
||||||
#[prost(message, tag = "64")]
|
#[prost(message, tag = "64")]
|
||||||
HidePaneWithIdPayload(super::HidePaneWithIdPayload),
|
HidePaneWithIdPayload(super::HidePaneWithIdPayload),
|
||||||
#[prost(message, tag = "65")]
|
#[prost(message, tag = "65")]
|
||||||
|
|
@ -132,6 +132,14 @@ pub mod plugin_command {
|
||||||
}
|
}
|
||||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
|
pub struct ReconfigurePayload {
|
||||||
|
#[prost(string, tag = "1")]
|
||||||
|
pub config: ::prost::alloc::string::String,
|
||||||
|
#[prost(bool, tag = "2")]
|
||||||
|
pub write_to_disk: bool,
|
||||||
|
}
|
||||||
|
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||||
|
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||||
pub struct RerunCommandPanePayload {
|
pub struct RerunCommandPanePayload {
|
||||||
#[prost(uint32, tag = "1")]
|
#[prost(uint32, tag = "1")]
|
||||||
pub terminal_pane_id: u32,
|
pub terminal_pane_id: u32,
|
||||||
|
|
|
||||||
|
|
@ -120,7 +120,7 @@ impl fmt::Display for KeyWithModifier {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|m| m.to_string())
|
.map(|m| m.to_string())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.join("-"),
|
.join(" "),
|
||||||
self.bare_key
|
self.bare_key
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -920,6 +920,7 @@ pub enum Event {
|
||||||
EditPaneOpened(u32, Context), // u32 - terminal_pane_id
|
EditPaneOpened(u32, Context), // u32 - terminal_pane_id
|
||||||
EditPaneExited(u32, Option<i32>, Context), // u32 - terminal_pane_id, Option<i32> - exit code
|
EditPaneExited(u32, Option<i32>, Context), // u32 - terminal_pane_id, Option<i32> - exit code
|
||||||
CommandPaneReRun(u32, Context), // u32 - terminal_pane_id, Option<i32> -
|
CommandPaneReRun(u32, Context), // u32 - terminal_pane_id, Option<i32> -
|
||||||
|
FailedToWriteConfigToDisk(Option<String>), // String -> the file path we failed to write
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
|
|
@ -1799,7 +1800,8 @@ pub enum PluginCommand {
|
||||||
DumpSessionLayout,
|
DumpSessionLayout,
|
||||||
CloseSelf,
|
CloseSelf,
|
||||||
NewTabsWithLayoutInfo(LayoutInfo),
|
NewTabsWithLayoutInfo(LayoutInfo),
|
||||||
Reconfigure(String), // String -> stringified configuration
|
Reconfigure(String, bool), // String -> stringified configuration, bool -> save configuration
|
||||||
|
// file to disk
|
||||||
HidePaneWithId(PaneId),
|
HidePaneWithId(PaneId),
|
||||||
ShowPaneWithId(PaneId, bool), // bool -> should_float_if_hidden
|
ShowPaneWithId(PaneId, bool), // bool -> should_float_if_hidden
|
||||||
OpenCommandPaneBackground(CommandToRun, Context),
|
OpenCommandPaneBackground(CommandToRun, Context),
|
||||||
|
|
|
||||||
|
|
@ -64,4 +64,7 @@ impl EnvironmentVariables {
|
||||||
set_var(k, v);
|
set_var(k, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn inner(&self) -> &HashMap<String, String> {
|
||||||
|
&self.env
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -411,6 +411,7 @@ pub enum PluginContext {
|
||||||
DumpLayoutToPlugin,
|
DumpLayoutToPlugin,
|
||||||
ListClientsMetadata,
|
ListClientsMetadata,
|
||||||
Reconfigure,
|
Reconfigure,
|
||||||
|
FailedToWriteConfigToDisk,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stack call representations corresponding to the different types of [`ClientInstruction`]s.
|
/// Stack call representations corresponding to the different types of [`ClientInstruction`]s.
|
||||||
|
|
@ -434,6 +435,7 @@ pub enum ClientContext {
|
||||||
UnblockCliPipeInput,
|
UnblockCliPipeInput,
|
||||||
CliPipeOutput,
|
CliPipeOutput,
|
||||||
QueryTerminalSize,
|
QueryTerminalSize,
|
||||||
|
WriteConfigToDisk,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stack call representations corresponding to the different types of [`ServerInstruction`]s.
|
/// Stack call representations corresponding to the different types of [`ServerInstruction`]s.
|
||||||
|
|
@ -460,6 +462,8 @@ pub enum ServerContext {
|
||||||
ChangeMode,
|
ChangeMode,
|
||||||
ChangeModeForAllClients,
|
ChangeModeForAllClients,
|
||||||
Reconfigure,
|
Reconfigure,
|
||||||
|
ConfigWrittenToDisk,
|
||||||
|
FailedToWriteConfigToDisk,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::data::Palette;
|
use crate::data::Palette;
|
||||||
use miette::{Diagnostic, LabeledSpan, NamedSource, SourceCode};
|
use miette::{Diagnostic, LabeledSpan, NamedSource, SourceCode};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{self, Read};
|
use std::io::{self, Read};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
@ -20,7 +21,7 @@ const DEFAULT_CONFIG_FILE_NAME: &str = "config.kdl";
|
||||||
type ConfigResult = Result<Config, ConfigError>;
|
type ConfigResult = Result<Config, ConfigError>;
|
||||||
|
|
||||||
/// Main configuration.
|
/// Main configuration.
|
||||||
#[derive(Debug, Clone, PartialEq, Default)]
|
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
pub keybinds: Keybinds,
|
pub keybinds: Keybinds,
|
||||||
pub options: Options,
|
pub options: Options,
|
||||||
|
|
@ -233,6 +234,164 @@ impl Config {
|
||||||
self.env = self.env.merge(other.env);
|
self.env = self.env.merge(other.env);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
fn config_file_path(opts: &CliArgs) -> Option<PathBuf> {
|
||||||
|
opts.config_dir
|
||||||
|
.clone()
|
||||||
|
.or_else(home::find_default_config_dir)
|
||||||
|
.map(|config_dir| config_dir.join(DEFAULT_CONFIG_FILE_NAME))
|
||||||
|
}
|
||||||
|
pub fn write_config_to_disk(config: String, opts: &CliArgs) -> Result<Config, Option<PathBuf>> {
|
||||||
|
// if we fail, try to return the PathBuf of the file we were not able to write to
|
||||||
|
Config::from_kdl(&config, None)
|
||||||
|
.map_err(|e| {
|
||||||
|
log::error!("Failed to parse config: {}", e);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
.and_then(|parsed_config| {
|
||||||
|
let backed_up_file_name = Config::backup_current_config(&opts)?;
|
||||||
|
let config_file_path = Config::config_file_path(&opts).ok_or_else(|| {
|
||||||
|
log::error!("Config file path not found");
|
||||||
|
None
|
||||||
|
})?;
|
||||||
|
let config = match backed_up_file_name {
|
||||||
|
Some(backed_up_file_name) => {
|
||||||
|
format!(
|
||||||
|
"{}{}",
|
||||||
|
Config::autogen_config_message(backed_up_file_name),
|
||||||
|
config
|
||||||
|
)
|
||||||
|
},
|
||||||
|
None => config,
|
||||||
|
};
|
||||||
|
std::fs::write(&config_file_path, config.as_bytes()).map_err(|e| {
|
||||||
|
log::error!("Failed to write config: {}", e);
|
||||||
|
Some(config_file_path.clone())
|
||||||
|
})?;
|
||||||
|
let written_config = std::fs::read_to_string(&config_file_path).map_err(|e| {
|
||||||
|
log::error!("Failed to read written config: {}", e);
|
||||||
|
Some(config_file_path.clone())
|
||||||
|
})?;
|
||||||
|
let parsed_written_config =
|
||||||
|
Config::from_kdl(&written_config, None).map_err(|e| {
|
||||||
|
log::error!("Failed to parse written config: {}", e);
|
||||||
|
None
|
||||||
|
})?;
|
||||||
|
if parsed_written_config == parsed_config {
|
||||||
|
Ok(parsed_config)
|
||||||
|
} else {
|
||||||
|
log::error!("Configuration corrupted when writing to disk");
|
||||||
|
Err(Some(config_file_path))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// returns true if the config was not previouly written to disk and we successfully wrote it
|
||||||
|
pub fn write_config_to_disk_if_it_does_not_exist(config: String, opts: &CliArgs) -> bool {
|
||||||
|
match Config::config_file_path(opts) {
|
||||||
|
Some(config_file_path) => {
|
||||||
|
if config_file_path.exists() {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
if let Err(e) = std::fs::write(&config_file_path, config.as_bytes()) {
|
||||||
|
log::error!("Failed to write config to disk: {}", e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
match std::fs::read_to_string(&config_file_path) {
|
||||||
|
Ok(written_config) => written_config == config,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to read written config: {}", e);
|
||||||
|
false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
None => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn find_free_backup_file_name(config_file_path: &PathBuf) -> Option<PathBuf> {
|
||||||
|
let mut backup_config_path = None;
|
||||||
|
let config_file_name = config_file_path
|
||||||
|
.file_name()
|
||||||
|
.and_then(|f| f.to_str())
|
||||||
|
.unwrap_or_else(|| DEFAULT_CONFIG_FILE_NAME);
|
||||||
|
for i in 0..100 {
|
||||||
|
let new_file_name = if i == 0 {
|
||||||
|
format!("{}.bak", config_file_name)
|
||||||
|
} else {
|
||||||
|
format!("{}.bak.{}", config_file_name, i)
|
||||||
|
};
|
||||||
|
let mut potential_config_path = config_file_path.clone();
|
||||||
|
potential_config_path.set_file_name(new_file_name);
|
||||||
|
if !potential_config_path.exists() {
|
||||||
|
backup_config_path = Some(potential_config_path);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
backup_config_path
|
||||||
|
}
|
||||||
|
fn backup_config_with_written_content_confirmation(
|
||||||
|
current_config: &str,
|
||||||
|
current_config_file_path: &PathBuf,
|
||||||
|
backup_config_path: &PathBuf,
|
||||||
|
) -> bool {
|
||||||
|
let _ = std::fs::copy(current_config_file_path, &backup_config_path);
|
||||||
|
match std::fs::read_to_string(&backup_config_path) {
|
||||||
|
Ok(backed_up_config) => current_config == &backed_up_config,
|
||||||
|
Err(e) => {
|
||||||
|
log::error!(
|
||||||
|
"Failed to back up config file {}: {:?}",
|
||||||
|
backup_config_path.display(),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
false
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn backup_current_config(opts: &CliArgs) -> Result<Option<PathBuf>, Option<PathBuf>> {
|
||||||
|
// if we fail, try to return the PathBuf of the file we were not able to write to
|
||||||
|
if let Some(config_file_path) = Config::config_file_path(&opts) {
|
||||||
|
match std::fs::read_to_string(&config_file_path) {
|
||||||
|
Ok(current_config) => {
|
||||||
|
let Some(backup_config_path) =
|
||||||
|
Config::find_free_backup_file_name(&config_file_path)
|
||||||
|
else {
|
||||||
|
log::error!("Failed to find a file name to back up the configuration to, ran out of files.");
|
||||||
|
return Err(None);
|
||||||
|
};
|
||||||
|
if Config::backup_config_with_written_content_confirmation(
|
||||||
|
¤t_config,
|
||||||
|
&config_file_path,
|
||||||
|
&backup_config_path,
|
||||||
|
) {
|
||||||
|
Ok(Some(backup_config_path))
|
||||||
|
} else {
|
||||||
|
log::error!(
|
||||||
|
"Failed to back up config file: {}",
|
||||||
|
backup_config_path.display()
|
||||||
|
);
|
||||||
|
Err(Some(backup_config_path))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
if e.kind() == std::io::ErrorKind::NotFound {
|
||||||
|
Ok(None)
|
||||||
|
} else {
|
||||||
|
log::error!(
|
||||||
|
"Failed to read current config {}: {}",
|
||||||
|
config_file_path.display(),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
Err(Some(config_file_path))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::error!("No config file path found?");
|
||||||
|
Err(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn autogen_config_message(backed_up_file_name: PathBuf) -> String {
|
||||||
|
format!("//\n// THIS FILE WAS AUTOGENERATED BY ZELLIJ, THE PREVIOUS FILE AT THIS LOCATION WAS COPIED TO: {}\n//\n\n", backed_up_file_name.display())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -463,6 +622,7 @@ mod config_test {
|
||||||
white: PaletteColor::Rgb((255, 255, 255)),
|
white: PaletteColor::Rgb((255, 255, 255)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
sourced_from_external_file: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let expected_themes = Themes::from_data(expected_themes);
|
let expected_themes = Themes::from_data(expected_themes);
|
||||||
|
|
@ -520,6 +680,7 @@ mod config_test {
|
||||||
white: PaletteColor::Rgb((255, 255, 255)),
|
white: PaletteColor::Rgb((255, 255, 255)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
sourced_from_external_file: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
expected_themes.insert(
|
expected_themes.insert(
|
||||||
|
|
@ -539,6 +700,7 @@ mod config_test {
|
||||||
orange: PaletteColor::Rgb((208, 135, 112)),
|
orange: PaletteColor::Rgb((208, 135, 112)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
sourced_from_external_file: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let expected_themes = Themes::from_data(expected_themes);
|
let expected_themes = Themes::from_data(expected_themes);
|
||||||
|
|
@ -583,6 +745,7 @@ mod config_test {
|
||||||
white: PaletteColor::EightBit(255),
|
white: PaletteColor::EightBit(255),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
},
|
},
|
||||||
|
sourced_from_external_file: false,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
let expected_themes = Themes::from_data(expected_themes);
|
let expected_themes = Themes::from_data(expected_themes);
|
||||||
|
|
|
||||||
|
|
@ -504,6 +504,12 @@ impl PluginUserConfiguration {
|
||||||
configuration.remove("direction");
|
configuration.remove("direction");
|
||||||
configuration.remove("floating");
|
configuration.remove("floating");
|
||||||
configuration.remove("move_to_focused_tab");
|
configuration.remove("move_to_focused_tab");
|
||||||
|
configuration.remove("launch_new");
|
||||||
|
configuration.remove("payload");
|
||||||
|
configuration.remove("skip_cache");
|
||||||
|
configuration.remove("title");
|
||||||
|
configuration.remove("in_place");
|
||||||
|
configuration.remove("skip_plugin_cache");
|
||||||
|
|
||||||
PluginUserConfiguration(configuration)
|
PluginUserConfiguration(configuration)
|
||||||
}
|
}
|
||||||
|
|
@ -735,6 +741,19 @@ pub struct FloatingPaneLayout {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FloatingPaneLayout {
|
impl FloatingPaneLayout {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
FloatingPaneLayout {
|
||||||
|
name: None,
|
||||||
|
height: None,
|
||||||
|
width: None,
|
||||||
|
x: None,
|
||||||
|
y: None,
|
||||||
|
run: None,
|
||||||
|
focus: None,
|
||||||
|
already_running: false,
|
||||||
|
pane_initial_contents: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
pub fn add_cwd_to_layout(&mut self, cwd: &PathBuf) {
|
pub fn add_cwd_to_layout(&mut self, cwd: &PathBuf) {
|
||||||
match self.run.as_mut() {
|
match self.run.as_mut() {
|
||||||
Some(run) => run.add_cwd(cwd),
|
Some(run) => run.add_cwd(cwd),
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ impl FrameConfig {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Default)]
|
#[derive(Clone, PartialEq, Default, Serialize, Deserialize)]
|
||||||
pub struct Themes(HashMap<String, Theme>);
|
pub struct Themes(HashMap<String, Theme>);
|
||||||
|
|
||||||
impl fmt::Debug for Themes {
|
impl fmt::Debug for Themes {
|
||||||
|
|
@ -67,12 +67,16 @@ impl Themes {
|
||||||
pub fn get_theme(&self, theme_name: &str) -> Option<&Theme> {
|
pub fn get_theme(&self, theme_name: &str) -> Option<&Theme> {
|
||||||
self.0.get(theme_name)
|
self.0.get(theme_name)
|
||||||
}
|
}
|
||||||
|
pub fn inner(&self) -> &HashMap<String, Theme> {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
|
||||||
pub struct Theme {
|
pub struct Theme {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub palette: Palette,
|
pub palette: Palette,
|
||||||
|
pub sourced_from_external_file: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
---
|
---
|
||||||
source: zellij-utils/src/input/./unit/theme_test.rs
|
source: zellij-utils/src/input/./unit/theme_test.rs
|
||||||
|
assertion_line: 15
|
||||||
expression: "format!(\"{:#?}\", theme)"
|
expression: "format!(\"{:#?}\", theme)"
|
||||||
---
|
---
|
||||||
{
|
{
|
||||||
|
|
@ -103,5 +104,6 @@ expression: "format!(\"{:#?}\", theme)"
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
sourced_from_external_file: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use crate::{
|
||||||
cli::CliArgs,
|
cli::CliArgs,
|
||||||
data::{ClientId, ConnectToSession, KeyWithModifier, Style},
|
data::{ClientId, ConnectToSession, KeyWithModifier, Style},
|
||||||
errors::{get_current_ctx, prelude::*, ErrorContext},
|
errors::{get_current_ctx, prelude::*, ErrorContext},
|
||||||
|
input::config::Config,
|
||||||
input::keybinds::Keybinds,
|
input::keybinds::Keybinds,
|
||||||
input::{actions::Action, layout::Layout, options::Options, plugins::PluginAliases},
|
input::{actions::Action, layout::Layout, options::Options, plugins::PluginAliases},
|
||||||
pane_size::{Size, SizeInPixels},
|
pane_size::{Size, SizeInPixels},
|
||||||
|
|
@ -16,6 +17,7 @@ use std::{
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
os::unix::io::{AsRawFd, FromRawFd},
|
os::unix::io::{AsRawFd, FromRawFd},
|
||||||
|
path::PathBuf,
|
||||||
};
|
};
|
||||||
|
|
||||||
type SessionId = u64;
|
type SessionId = u64;
|
||||||
|
|
@ -41,7 +43,6 @@ pub enum ClientType {
|
||||||
pub struct ClientAttributes {
|
pub struct ClientAttributes {
|
||||||
pub size: Size,
|
pub size: Size,
|
||||||
pub style: Style,
|
pub style: Style,
|
||||||
pub keybinds: Keybinds,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Default, Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
|
@ -74,13 +75,16 @@ pub enum ClientToServerMsg {
|
||||||
NewClient(
|
NewClient(
|
||||||
ClientAttributes,
|
ClientAttributes,
|
||||||
Box<CliArgs>,
|
Box<CliArgs>,
|
||||||
Box<Options>,
|
Box<Config>, // represents the saved configuration
|
||||||
|
Box<Options>, // represents the runtime configuration
|
||||||
Box<Layout>,
|
Box<Layout>,
|
||||||
Box<PluginAliases>,
|
Box<PluginAliases>,
|
||||||
|
bool, // should launch setup wizard
|
||||||
),
|
),
|
||||||
AttachClient(
|
AttachClient(
|
||||||
ClientAttributes,
|
ClientAttributes,
|
||||||
Options,
|
Config, // represents the saved configuration
|
||||||
|
Options, // represents the runtime configuration
|
||||||
Option<usize>, // tab position to focus
|
Option<usize>, // tab position to focus
|
||||||
Option<(u32, bool)>, // (pane_id, is_plugin) => pane id to focus
|
Option<(u32, bool)>, // (pane_id, is_plugin) => pane id to focus
|
||||||
),
|
),
|
||||||
|
|
@ -90,6 +94,8 @@ pub enum ClientToServerMsg {
|
||||||
KillSession,
|
KillSession,
|
||||||
ConnStatus,
|
ConnStatus,
|
||||||
ListClients,
|
ListClients,
|
||||||
|
ConfigWrittenToDisk(Config),
|
||||||
|
FailedToWriteConfigToDisk(Option<PathBuf>),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Types of messages sent from the server to the client
|
// Types of messages sent from the server to the client
|
||||||
|
|
@ -106,6 +112,7 @@ pub enum ServerToClientMsg {
|
||||||
UnblockCliPipeInput(String), // String -> pipe name
|
UnblockCliPipeInput(String), // String -> pipe name
|
||||||
CliPipeOutput(String, String), // String -> pipe name, String -> Output
|
CliPipeOutput(String, String), // String -> pipe name, String -> Output
|
||||||
QueryTerminalSize,
|
QueryTerminalSize,
|
||||||
|
WriteConfigToDisk { config: String },
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,240 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 5060
|
||||||
|
expression: fake_config_stringified
|
||||||
|
---
|
||||||
|
keybinds clear-defaults=true {
|
||||||
|
locked {
|
||||||
|
bind "Ctrl g" { SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
pane {
|
||||||
|
bind "left" { MoveFocus "left"; }
|
||||||
|
bind "down" { MoveFocus "down"; }
|
||||||
|
bind "up" { MoveFocus "up"; }
|
||||||
|
bind "right" { MoveFocus "right"; }
|
||||||
|
bind "c" { SwitchToMode "renamepane"; PaneNameInput 0; }
|
||||||
|
bind "d" { NewPane "down"; SwitchToMode "normal"; }
|
||||||
|
bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; }
|
||||||
|
bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; }
|
||||||
|
bind "h" { MoveFocus "left"; }
|
||||||
|
bind "j" { MoveFocus "down"; }
|
||||||
|
bind "k" { MoveFocus "up"; }
|
||||||
|
bind "l" { MoveFocus "right"; }
|
||||||
|
bind "n" { NewPane; SwitchToMode "normal"; }
|
||||||
|
bind "p" { SwitchFocus; }
|
||||||
|
bind "Ctrl p" { SwitchToMode "normal"; }
|
||||||
|
bind "r" { NewPane "right"; SwitchToMode "normal"; }
|
||||||
|
bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; }
|
||||||
|
bind "z" { TogglePaneFrames; SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
tab {
|
||||||
|
bind "left" { GoToPreviousTab; }
|
||||||
|
bind "down" { GoToNextTab; }
|
||||||
|
bind "up" { GoToPreviousTab; }
|
||||||
|
bind "right" { GoToNextTab; }
|
||||||
|
bind "1" { GoToTab 1; SwitchToMode "normal"; }
|
||||||
|
bind "2" { GoToTab 2; SwitchToMode "normal"; }
|
||||||
|
bind "3" { GoToTab 3; SwitchToMode "normal"; }
|
||||||
|
bind "4" { GoToTab 4; SwitchToMode "normal"; }
|
||||||
|
bind "5" { GoToTab 5; SwitchToMode "normal"; }
|
||||||
|
bind "6" { GoToTab 6; SwitchToMode "normal"; }
|
||||||
|
bind "7" { GoToTab 7; SwitchToMode "normal"; }
|
||||||
|
bind "8" { GoToTab 8; SwitchToMode "normal"; }
|
||||||
|
bind "9" { GoToTab 9; SwitchToMode "normal"; }
|
||||||
|
bind "[" { BreakPaneLeft; SwitchToMode "normal"; }
|
||||||
|
bind "]" { BreakPaneRight; SwitchToMode "normal"; }
|
||||||
|
bind "b" { BreakPane; SwitchToMode "normal"; }
|
||||||
|
bind "h" { GoToPreviousTab; }
|
||||||
|
bind "j" { GoToNextTab; }
|
||||||
|
bind "k" { GoToPreviousTab; }
|
||||||
|
bind "l" { GoToNextTab; }
|
||||||
|
bind "n" { NewTab; SwitchToMode "normal"; }
|
||||||
|
bind "r" { SwitchToMode "renametab"; TabNameInput 0; }
|
||||||
|
bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; }
|
||||||
|
bind "Ctrl t" { SwitchToMode "normal"; }
|
||||||
|
bind "x" { CloseTab; SwitchToMode "normal"; }
|
||||||
|
bind "tab" { ToggleTab; }
|
||||||
|
}
|
||||||
|
resize {
|
||||||
|
bind "left" { Resize "Increase left"; }
|
||||||
|
bind "down" { Resize "Increase down"; }
|
||||||
|
bind "up" { Resize "Increase up"; }
|
||||||
|
bind "right" { Resize "Increase right"; }
|
||||||
|
bind "+" { Resize "Increase"; }
|
||||||
|
bind "-" { Resize "Decrease"; }
|
||||||
|
bind "=" { Resize "Increase"; }
|
||||||
|
bind "H" { Resize "Decrease left"; }
|
||||||
|
bind "J" { Resize "Decrease down"; }
|
||||||
|
bind "K" { Resize "Decrease up"; }
|
||||||
|
bind "L" { Resize "Decrease right"; }
|
||||||
|
bind "h" { Resize "Increase left"; }
|
||||||
|
bind "j" { Resize "Increase down"; }
|
||||||
|
bind "k" { Resize "Increase up"; }
|
||||||
|
bind "l" { Resize "Increase right"; }
|
||||||
|
bind "Ctrl n" { SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
move {
|
||||||
|
bind "left" { MovePane "left"; }
|
||||||
|
bind "down" { MovePane "down"; }
|
||||||
|
bind "up" { MovePane "up"; }
|
||||||
|
bind "right" { MovePane "right"; }
|
||||||
|
bind "h" { MovePane "left"; }
|
||||||
|
bind "Ctrl h" { SwitchToMode "normal"; }
|
||||||
|
bind "j" { MovePane "down"; }
|
||||||
|
bind "k" { MovePane "up"; }
|
||||||
|
bind "l" { MovePane "right"; }
|
||||||
|
bind "n" { MovePane; }
|
||||||
|
bind "p" { MovePaneBackwards; }
|
||||||
|
bind "tab" { MovePane; }
|
||||||
|
}
|
||||||
|
scroll {
|
||||||
|
bind "e" { EditScrollback; SwitchToMode "normal"; }
|
||||||
|
bind "s" { SwitchToMode "entersearch"; SearchInput 0; }
|
||||||
|
}
|
||||||
|
search {
|
||||||
|
bind "c" { SearchToggleOption "CaseSensitivity"; }
|
||||||
|
bind "n" { Search "down"; }
|
||||||
|
bind "o" { SearchToggleOption "WholeWord"; }
|
||||||
|
bind "p" { Search "up"; }
|
||||||
|
bind "w" { SearchToggleOption "Wrap"; }
|
||||||
|
}
|
||||||
|
session {
|
||||||
|
bind "c" {
|
||||||
|
LaunchOrFocusPlugin "configuration" {
|
||||||
|
floating true
|
||||||
|
move_to_focused_tab true
|
||||||
|
}
|
||||||
|
SwitchToMode "normal"
|
||||||
|
}
|
||||||
|
bind "Ctrl o" { SwitchToMode "normal"; }
|
||||||
|
bind "w" {
|
||||||
|
LaunchOrFocusPlugin "session-manager" {
|
||||||
|
floating true
|
||||||
|
move_to_focused_tab true
|
||||||
|
}
|
||||||
|
SwitchToMode "normal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shared_except "locked" {
|
||||||
|
bind "Alt left" { MoveFocusOrTab "left"; }
|
||||||
|
bind "Alt down" { MoveFocus "down"; }
|
||||||
|
bind "Alt up" { MoveFocus "up"; }
|
||||||
|
bind "Alt right" { MoveFocusOrTab "right"; }
|
||||||
|
bind "Alt +" { Resize "Increase"; }
|
||||||
|
bind "Alt -" { Resize "Decrease"; }
|
||||||
|
bind "Alt =" { Resize "Increase"; }
|
||||||
|
bind "Alt [" { PreviousSwapLayout; }
|
||||||
|
bind "Alt ]" { NextSwapLayout; }
|
||||||
|
bind "Alt f" { ToggleFloatingPanes; }
|
||||||
|
bind "Ctrl g" { SwitchToMode "locked"; }
|
||||||
|
bind "Alt h" { MoveFocusOrTab "left"; }
|
||||||
|
bind "Alt i" { MoveTab "left"; }
|
||||||
|
bind "Alt j" { MoveFocus "down"; }
|
||||||
|
bind "Alt k" { MoveFocus "up"; }
|
||||||
|
bind "Alt l" { MoveFocusOrTab "right"; }
|
||||||
|
bind "Alt n" { NewPane; }
|
||||||
|
bind "Alt o" { MoveTab "right"; }
|
||||||
|
bind "Ctrl q" { Quit; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "move" {
|
||||||
|
bind "Ctrl h" { SwitchToMode "move"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "session" {
|
||||||
|
bind "Ctrl o" { SwitchToMode "session"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "scroll" "search" "tmux" {
|
||||||
|
bind "Ctrl b" { SwitchToMode "tmux"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "scroll" "search" {
|
||||||
|
bind "Ctrl s" { SwitchToMode "scroll"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "tab" {
|
||||||
|
bind "Ctrl t" { SwitchToMode "tab"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "pane" {
|
||||||
|
bind "Ctrl p" { SwitchToMode "pane"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "resize" {
|
||||||
|
bind "Ctrl n" { SwitchToMode "resize"; }
|
||||||
|
}
|
||||||
|
shared_except "normal" "locked" "entersearch" {
|
||||||
|
bind "enter" { SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
shared_except "normal" "locked" "entersearch" "renametab" "renamepane" {
|
||||||
|
bind "esc" { SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
shared_among "pane" "tmux" {
|
||||||
|
bind "x" { CloseFocus; SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
shared_among "scroll" "search" {
|
||||||
|
bind "PageDown" { PageScrollDown; }
|
||||||
|
bind "PageUp" { PageScrollUp; }
|
||||||
|
bind "left" { PageScrollUp; }
|
||||||
|
bind "down" { ScrollDown; }
|
||||||
|
bind "up" { ScrollUp; }
|
||||||
|
bind "right" { PageScrollDown; }
|
||||||
|
bind "Ctrl b" { PageScrollUp; }
|
||||||
|
bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; }
|
||||||
|
bind "d" { HalfPageScrollDown; }
|
||||||
|
bind "Ctrl f" { PageScrollDown; }
|
||||||
|
bind "h" { PageScrollUp; }
|
||||||
|
bind "j" { ScrollDown; }
|
||||||
|
bind "k" { ScrollUp; }
|
||||||
|
bind "l" { PageScrollDown; }
|
||||||
|
bind "Ctrl s" { SwitchToMode "normal"; }
|
||||||
|
bind "u" { HalfPageScrollUp; }
|
||||||
|
}
|
||||||
|
entersearch {
|
||||||
|
bind "Ctrl c" { SwitchToMode "scroll"; }
|
||||||
|
bind "esc" { SwitchToMode "scroll"; }
|
||||||
|
bind "enter" { SwitchToMode "search"; }
|
||||||
|
}
|
||||||
|
renametab {
|
||||||
|
bind "esc" { UndoRenameTab; SwitchToMode "tab"; }
|
||||||
|
}
|
||||||
|
shared_among "renametab" "renamepane" {
|
||||||
|
bind "Ctrl c" { SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
renamepane {
|
||||||
|
bind "esc" { UndoRenamePane; SwitchToMode "pane"; }
|
||||||
|
}
|
||||||
|
shared_among "session" "tmux" {
|
||||||
|
bind "d" { Detach; }
|
||||||
|
}
|
||||||
|
tmux {
|
||||||
|
bind "left" { MoveFocus "left"; SwitchToMode "normal"; }
|
||||||
|
bind "down" { MoveFocus "down"; SwitchToMode "normal"; }
|
||||||
|
bind "up" { MoveFocus "up"; SwitchToMode "normal"; }
|
||||||
|
bind "right" { MoveFocus "right"; SwitchToMode "normal"; }
|
||||||
|
bind "space" { NextSwapLayout; }
|
||||||
|
bind "\"" { NewPane "down"; SwitchToMode "normal"; }
|
||||||
|
bind "%" { NewPane "right"; SwitchToMode "normal"; }
|
||||||
|
bind "," { SwitchToMode "renametab"; }
|
||||||
|
bind "[" { SwitchToMode "scroll"; }
|
||||||
|
bind "Ctrl b" { Write 2; SwitchToMode "normal"; }
|
||||||
|
bind "c" { NewTab; SwitchToMode "normal"; }
|
||||||
|
bind "h" { MoveFocus "left"; SwitchToMode "normal"; }
|
||||||
|
bind "j" { MoveFocus "down"; SwitchToMode "normal"; }
|
||||||
|
bind "k" { MoveFocus "up"; SwitchToMode "normal"; }
|
||||||
|
bind "l" { MoveFocus "right"; SwitchToMode "normal"; }
|
||||||
|
bind "n" { GoToNextTab; SwitchToMode "normal"; }
|
||||||
|
bind "o" { FocusNextPane; }
|
||||||
|
bind "p" { GoToPreviousTab; SwitchToMode "normal"; }
|
||||||
|
bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plugins {
|
||||||
|
compact-bar location="zellij:compact-bar"
|
||||||
|
configuration location="zellij:configuration"
|
||||||
|
filepicker location="zellij:strider" {
|
||||||
|
cwd "/"
|
||||||
|
}
|
||||||
|
session-manager location="zellij:session-manager"
|
||||||
|
status-bar location="zellij:status-bar"
|
||||||
|
strider location="zellij:strider"
|
||||||
|
tab-bar location="zellij:tab-bar"
|
||||||
|
welcome-screen location="zellij:session-manager" {
|
||||||
|
welcome_screen true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,409 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 5069
|
||||||
|
expression: fake_config_stringified
|
||||||
|
---
|
||||||
|
keybinds clear-defaults=true {
|
||||||
|
locked {
|
||||||
|
bind "Ctrl g" { SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
pane {
|
||||||
|
bind "left" { MoveFocus "left"; }
|
||||||
|
bind "down" { MoveFocus "down"; }
|
||||||
|
bind "up" { MoveFocus "up"; }
|
||||||
|
bind "right" { MoveFocus "right"; }
|
||||||
|
bind "c" { SwitchToMode "renamepane"; PaneNameInput 0; }
|
||||||
|
bind "d" { NewPane "down"; SwitchToMode "normal"; }
|
||||||
|
bind "e" { TogglePaneEmbedOrFloating; SwitchToMode "normal"; }
|
||||||
|
bind "f" { ToggleFocusFullscreen; SwitchToMode "normal"; }
|
||||||
|
bind "h" { MoveFocus "left"; }
|
||||||
|
bind "j" { MoveFocus "down"; }
|
||||||
|
bind "k" { MoveFocus "up"; }
|
||||||
|
bind "l" { MoveFocus "right"; }
|
||||||
|
bind "n" { NewPane; SwitchToMode "normal"; }
|
||||||
|
bind "p" { SwitchFocus; }
|
||||||
|
bind "Ctrl p" { SwitchToMode "normal"; }
|
||||||
|
bind "r" { NewPane "right"; SwitchToMode "normal"; }
|
||||||
|
bind "w" { ToggleFloatingPanes; SwitchToMode "normal"; }
|
||||||
|
bind "z" { TogglePaneFrames; SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
tab {
|
||||||
|
bind "left" { GoToPreviousTab; }
|
||||||
|
bind "down" { GoToNextTab; }
|
||||||
|
bind "up" { GoToPreviousTab; }
|
||||||
|
bind "right" { GoToNextTab; }
|
||||||
|
bind "1" { GoToTab 1; SwitchToMode "normal"; }
|
||||||
|
bind "2" { GoToTab 2; SwitchToMode "normal"; }
|
||||||
|
bind "3" { GoToTab 3; SwitchToMode "normal"; }
|
||||||
|
bind "4" { GoToTab 4; SwitchToMode "normal"; }
|
||||||
|
bind "5" { GoToTab 5; SwitchToMode "normal"; }
|
||||||
|
bind "6" { GoToTab 6; SwitchToMode "normal"; }
|
||||||
|
bind "7" { GoToTab 7; SwitchToMode "normal"; }
|
||||||
|
bind "8" { GoToTab 8; SwitchToMode "normal"; }
|
||||||
|
bind "9" { GoToTab 9; SwitchToMode "normal"; }
|
||||||
|
bind "[" { BreakPaneLeft; SwitchToMode "normal"; }
|
||||||
|
bind "]" { BreakPaneRight; SwitchToMode "normal"; }
|
||||||
|
bind "b" { BreakPane; SwitchToMode "normal"; }
|
||||||
|
bind "h" { GoToPreviousTab; }
|
||||||
|
bind "j" { GoToNextTab; }
|
||||||
|
bind "k" { GoToPreviousTab; }
|
||||||
|
bind "l" { GoToNextTab; }
|
||||||
|
bind "n" { NewTab; SwitchToMode "normal"; }
|
||||||
|
bind "r" { SwitchToMode "renametab"; TabNameInput 0; }
|
||||||
|
bind "s" { ToggleActiveSyncTab; SwitchToMode "normal"; }
|
||||||
|
bind "Ctrl t" { SwitchToMode "normal"; }
|
||||||
|
bind "x" { CloseTab; SwitchToMode "normal"; }
|
||||||
|
bind "tab" { ToggleTab; }
|
||||||
|
}
|
||||||
|
resize {
|
||||||
|
bind "left" { Resize "Increase left"; }
|
||||||
|
bind "down" { Resize "Increase down"; }
|
||||||
|
bind "up" { Resize "Increase up"; }
|
||||||
|
bind "right" { Resize "Increase right"; }
|
||||||
|
bind "+" { Resize "Increase"; }
|
||||||
|
bind "-" { Resize "Decrease"; }
|
||||||
|
bind "=" { Resize "Increase"; }
|
||||||
|
bind "H" { Resize "Decrease left"; }
|
||||||
|
bind "J" { Resize "Decrease down"; }
|
||||||
|
bind "K" { Resize "Decrease up"; }
|
||||||
|
bind "L" { Resize "Decrease right"; }
|
||||||
|
bind "h" { Resize "Increase left"; }
|
||||||
|
bind "j" { Resize "Increase down"; }
|
||||||
|
bind "k" { Resize "Increase up"; }
|
||||||
|
bind "l" { Resize "Increase right"; }
|
||||||
|
bind "Ctrl n" { SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
move {
|
||||||
|
bind "left" { MovePane "left"; }
|
||||||
|
bind "down" { MovePane "down"; }
|
||||||
|
bind "up" { MovePane "up"; }
|
||||||
|
bind "right" { MovePane "right"; }
|
||||||
|
bind "h" { MovePane "left"; }
|
||||||
|
bind "Ctrl h" { SwitchToMode "normal"; }
|
||||||
|
bind "j" { MovePane "down"; }
|
||||||
|
bind "k" { MovePane "up"; }
|
||||||
|
bind "l" { MovePane "right"; }
|
||||||
|
bind "n" { MovePane; }
|
||||||
|
bind "p" { MovePaneBackwards; }
|
||||||
|
bind "tab" { MovePane; }
|
||||||
|
}
|
||||||
|
scroll {
|
||||||
|
bind "e" { EditScrollback; SwitchToMode "normal"; }
|
||||||
|
bind "s" { SwitchToMode "entersearch"; SearchInput 0; }
|
||||||
|
}
|
||||||
|
search {
|
||||||
|
bind "c" { SearchToggleOption "CaseSensitivity"; }
|
||||||
|
bind "n" { Search "down"; }
|
||||||
|
bind "o" { SearchToggleOption "WholeWord"; }
|
||||||
|
bind "p" { Search "up"; }
|
||||||
|
bind "w" { SearchToggleOption "Wrap"; }
|
||||||
|
}
|
||||||
|
session {
|
||||||
|
bind "c" {
|
||||||
|
LaunchOrFocusPlugin "configuration" {
|
||||||
|
floating true
|
||||||
|
move_to_focused_tab true
|
||||||
|
}
|
||||||
|
SwitchToMode "normal"
|
||||||
|
}
|
||||||
|
bind "Ctrl o" { SwitchToMode "normal"; }
|
||||||
|
bind "w" {
|
||||||
|
LaunchOrFocusPlugin "session-manager" {
|
||||||
|
floating true
|
||||||
|
move_to_focused_tab true
|
||||||
|
}
|
||||||
|
SwitchToMode "normal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
shared_except "locked" {
|
||||||
|
bind "Alt left" { MoveFocusOrTab "left"; }
|
||||||
|
bind "Alt down" { MoveFocus "down"; }
|
||||||
|
bind "Alt up" { MoveFocus "up"; }
|
||||||
|
bind "Alt right" { MoveFocusOrTab "right"; }
|
||||||
|
bind "Alt +" { Resize "Increase"; }
|
||||||
|
bind "Alt -" { Resize "Decrease"; }
|
||||||
|
bind "Alt =" { Resize "Increase"; }
|
||||||
|
bind "Alt [" { PreviousSwapLayout; }
|
||||||
|
bind "Alt ]" { NextSwapLayout; }
|
||||||
|
bind "Alt f" { ToggleFloatingPanes; }
|
||||||
|
bind "Ctrl g" { SwitchToMode "locked"; }
|
||||||
|
bind "Alt h" { MoveFocusOrTab "left"; }
|
||||||
|
bind "Alt i" { MoveTab "left"; }
|
||||||
|
bind "Alt j" { MoveFocus "down"; }
|
||||||
|
bind "Alt k" { MoveFocus "up"; }
|
||||||
|
bind "Alt l" { MoveFocusOrTab "right"; }
|
||||||
|
bind "Alt n" { NewPane; }
|
||||||
|
bind "Alt o" { MoveTab "right"; }
|
||||||
|
bind "Ctrl q" { Quit; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "move" {
|
||||||
|
bind "Ctrl h" { SwitchToMode "move"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "session" {
|
||||||
|
bind "Ctrl o" { SwitchToMode "session"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "scroll" "search" "tmux" {
|
||||||
|
bind "Ctrl b" { SwitchToMode "tmux"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "scroll" "search" {
|
||||||
|
bind "Ctrl s" { SwitchToMode "scroll"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "tab" {
|
||||||
|
bind "Ctrl t" { SwitchToMode "tab"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "pane" {
|
||||||
|
bind "Ctrl p" { SwitchToMode "pane"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "resize" {
|
||||||
|
bind "Ctrl n" { SwitchToMode "resize"; }
|
||||||
|
}
|
||||||
|
shared_except "normal" "locked" "entersearch" {
|
||||||
|
bind "enter" { SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
shared_except "normal" "locked" "entersearch" "renametab" "renamepane" {
|
||||||
|
bind "esc" { SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
shared_among "pane" "tmux" {
|
||||||
|
bind "x" { CloseFocus; SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
shared_among "scroll" "search" {
|
||||||
|
bind "PageDown" { PageScrollDown; }
|
||||||
|
bind "PageUp" { PageScrollUp; }
|
||||||
|
bind "left" { PageScrollUp; }
|
||||||
|
bind "down" { ScrollDown; }
|
||||||
|
bind "up" { ScrollUp; }
|
||||||
|
bind "right" { PageScrollDown; }
|
||||||
|
bind "Ctrl b" { PageScrollUp; }
|
||||||
|
bind "Ctrl c" { ScrollToBottom; SwitchToMode "normal"; }
|
||||||
|
bind "d" { HalfPageScrollDown; }
|
||||||
|
bind "Ctrl f" { PageScrollDown; }
|
||||||
|
bind "h" { PageScrollUp; }
|
||||||
|
bind "j" { ScrollDown; }
|
||||||
|
bind "k" { ScrollUp; }
|
||||||
|
bind "l" { PageScrollDown; }
|
||||||
|
bind "Ctrl s" { SwitchToMode "normal"; }
|
||||||
|
bind "u" { HalfPageScrollUp; }
|
||||||
|
}
|
||||||
|
entersearch {
|
||||||
|
bind "Ctrl c" { SwitchToMode "scroll"; }
|
||||||
|
bind "esc" { SwitchToMode "scroll"; }
|
||||||
|
bind "enter" { SwitchToMode "search"; }
|
||||||
|
}
|
||||||
|
renametab {
|
||||||
|
bind "esc" { UndoRenameTab; SwitchToMode "tab"; }
|
||||||
|
}
|
||||||
|
shared_among "renametab" "renamepane" {
|
||||||
|
bind "Ctrl c" { SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
renamepane {
|
||||||
|
bind "esc" { UndoRenamePane; SwitchToMode "pane"; }
|
||||||
|
}
|
||||||
|
shared_among "session" "tmux" {
|
||||||
|
bind "d" { Detach; }
|
||||||
|
}
|
||||||
|
tmux {
|
||||||
|
bind "left" { MoveFocus "left"; SwitchToMode "normal"; }
|
||||||
|
bind "down" { MoveFocus "down"; SwitchToMode "normal"; }
|
||||||
|
bind "up" { MoveFocus "up"; SwitchToMode "normal"; }
|
||||||
|
bind "right" { MoveFocus "right"; SwitchToMode "normal"; }
|
||||||
|
bind "space" { NextSwapLayout; }
|
||||||
|
bind "\"" { NewPane "down"; SwitchToMode "normal"; }
|
||||||
|
bind "%" { NewPane "right"; SwitchToMode "normal"; }
|
||||||
|
bind "," { SwitchToMode "renametab"; }
|
||||||
|
bind "[" { SwitchToMode "scroll"; }
|
||||||
|
bind "Ctrl b" { Write 2; SwitchToMode "normal"; }
|
||||||
|
bind "c" { NewTab; SwitchToMode "normal"; }
|
||||||
|
bind "h" { MoveFocus "left"; SwitchToMode "normal"; }
|
||||||
|
bind "j" { MoveFocus "down"; SwitchToMode "normal"; }
|
||||||
|
bind "k" { MoveFocus "up"; SwitchToMode "normal"; }
|
||||||
|
bind "l" { MoveFocus "right"; SwitchToMode "normal"; }
|
||||||
|
bind "n" { GoToNextTab; SwitchToMode "normal"; }
|
||||||
|
bind "o" { FocusNextPane; }
|
||||||
|
bind "p" { GoToPreviousTab; SwitchToMode "normal"; }
|
||||||
|
bind "z" { ToggleFocusFullscreen; SwitchToMode "normal"; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
plugins {
|
||||||
|
compact-bar location="zellij:compact-bar"
|
||||||
|
configuration location="zellij:configuration"
|
||||||
|
filepicker location="zellij:strider" {
|
||||||
|
cwd "/"
|
||||||
|
}
|
||||||
|
session-manager location="zellij:session-manager"
|
||||||
|
status-bar location="zellij:status-bar"
|
||||||
|
strider location="zellij:strider"
|
||||||
|
tab-bar location="zellij:tab-bar"
|
||||||
|
welcome-screen location="zellij:session-manager" {
|
||||||
|
welcome_screen true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use a simplified UI without special fonts (arrow glyphs)
|
||||||
|
// Options:
|
||||||
|
// - true
|
||||||
|
// - false (Default)
|
||||||
|
//
|
||||||
|
// simplified_ui true
|
||||||
|
|
||||||
|
// Choose the theme that is specified in the themes section.
|
||||||
|
// Default: default
|
||||||
|
//
|
||||||
|
// theme "dracula"
|
||||||
|
|
||||||
|
// Choose the base input mode of zellij.
|
||||||
|
// Default: normal
|
||||||
|
//
|
||||||
|
// default_mode "locked"
|
||||||
|
|
||||||
|
// Choose the path to the default shell that zellij will use for opening new panes
|
||||||
|
// Default: $SHELL
|
||||||
|
//
|
||||||
|
// default_shell "fish"
|
||||||
|
|
||||||
|
// Choose the path to override cwd that zellij will use for opening new panes
|
||||||
|
//
|
||||||
|
// default_cwd "/tmp"
|
||||||
|
|
||||||
|
// The name of the default layout to load on startup
|
||||||
|
// Default: "default"
|
||||||
|
//
|
||||||
|
// default_layout "compact"
|
||||||
|
|
||||||
|
// The folder in which Zellij will look for layouts
|
||||||
|
//
|
||||||
|
// layout_dir "/tmp"
|
||||||
|
|
||||||
|
// The folder in which Zellij will look for themes
|
||||||
|
//
|
||||||
|
// theme_dir "/tmp"
|
||||||
|
|
||||||
|
// Toggle enabling the mouse mode.
|
||||||
|
// On certain configurations, or terminals this could
|
||||||
|
// potentially interfere with copying text.
|
||||||
|
// Options:
|
||||||
|
// - true (default)
|
||||||
|
// - false
|
||||||
|
//
|
||||||
|
// mouse_mode false
|
||||||
|
|
||||||
|
// Toggle having pane frames around the panes
|
||||||
|
// Options:
|
||||||
|
// - true (default, enabled)
|
||||||
|
// - false
|
||||||
|
//
|
||||||
|
// pane_frames false
|
||||||
|
|
||||||
|
// When attaching to an existing session with other users,
|
||||||
|
// should the session be mirrored (true)
|
||||||
|
// or should each user have their own cursor (false)
|
||||||
|
// Default: false
|
||||||
|
//
|
||||||
|
// mirror_session true
|
||||||
|
|
||||||
|
// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP
|
||||||
|
// eg. when terminal window with an active zellij session is closed
|
||||||
|
// Options:
|
||||||
|
// - detach (Default)
|
||||||
|
// - quit
|
||||||
|
//
|
||||||
|
// on_force_close "quit"
|
||||||
|
|
||||||
|
// Configure the scroll back buffer size
|
||||||
|
// This is the number of lines zellij stores for each pane in the scroll back
|
||||||
|
// buffer. Excess number of lines are discarded in a FIFO fashion.
|
||||||
|
// Valid values: positive integers
|
||||||
|
// Default value: 10000
|
||||||
|
//
|
||||||
|
// scroll_buffer_size 10000
|
||||||
|
|
||||||
|
// Provide a command to execute when copying text. The text will be piped to
|
||||||
|
// the stdin of the program to perform the copy. This can be used with
|
||||||
|
// terminal emulators which do not support the OSC 52 ANSI control sequence
|
||||||
|
// that will be used by default if this option is not set.
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// copy_command "xclip -selection clipboard" // x11
|
||||||
|
// copy_command "wl-copy" // wayland
|
||||||
|
// copy_command "pbcopy" // osx
|
||||||
|
//
|
||||||
|
// copy_command "pbcopy"
|
||||||
|
|
||||||
|
// Choose the destination for copied text
|
||||||
|
// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard.
|
||||||
|
// Does not apply when using copy_command.
|
||||||
|
// Options:
|
||||||
|
// - system (default)
|
||||||
|
// - primary
|
||||||
|
//
|
||||||
|
// copy_clipboard "primary"
|
||||||
|
|
||||||
|
// Enable automatic copying (and clearing) of selection when releasing mouse
|
||||||
|
// Default: true
|
||||||
|
//
|
||||||
|
// copy_on_select true
|
||||||
|
|
||||||
|
// Path to the default editor to use to edit pane scrollbuffer
|
||||||
|
// Default: $EDITOR or $VISUAL
|
||||||
|
// scrollback_editor "/usr/bin/vim"
|
||||||
|
|
||||||
|
// A fixed name to always give the Zellij session.
|
||||||
|
// Consider also setting `attach_to_session true,`
|
||||||
|
// otherwise this will error if such a session exists.
|
||||||
|
// Default: <RANDOM>
|
||||||
|
//
|
||||||
|
// session_name "My singleton session"
|
||||||
|
|
||||||
|
// When `session_name` is provided, attaches to that session
|
||||||
|
// if it is already running or creates it otherwise.
|
||||||
|
// Default: false
|
||||||
|
//
|
||||||
|
// attach_to_session true
|
||||||
|
|
||||||
|
// Toggle between having Zellij lay out panes according to a predefined set of layouts whenever possible
|
||||||
|
// Options:
|
||||||
|
// - true (default)
|
||||||
|
// - false
|
||||||
|
//
|
||||||
|
// auto_layout false
|
||||||
|
|
||||||
|
// Whether sessions should be serialized to the cache folder (including their tabs/panes, cwds and running commands) so that they can later be resurrected
|
||||||
|
// Options:
|
||||||
|
// - true (default)
|
||||||
|
// - false
|
||||||
|
//
|
||||||
|
// session_serialization false
|
||||||
|
|
||||||
|
// Whether pane viewports are serialized along with the session, default is false
|
||||||
|
// Options:
|
||||||
|
// - true
|
||||||
|
// - false (default)
|
||||||
|
//
|
||||||
|
// serialize_pane_viewport false
|
||||||
|
|
||||||
|
// Scrollback lines to serialize along with the pane viewport when serializing sessions, 0
|
||||||
|
// defaults to the scrollback size. If this number is higher than the scrollback size, it will
|
||||||
|
// also default to the scrollback size. This does nothing if `serialize_pane_viewport` is not true.
|
||||||
|
//
|
||||||
|
// scrollback_lines_to_serialize 10000
|
||||||
|
|
||||||
|
// Enable or disable the rendering of styled and colored underlines (undercurl).
|
||||||
|
// May need to be disabled for certain unsupported terminals
|
||||||
|
// Default: true
|
||||||
|
//
|
||||||
|
// styled_underlines false
|
||||||
|
|
||||||
|
// How often in seconds sessions are serialized
|
||||||
|
//
|
||||||
|
// serialization_interval 10000
|
||||||
|
|
||||||
|
// Enable or disable writing of session metadata to disk (if disabled, other sessions might not know
|
||||||
|
// metadata info on this session)
|
||||||
|
// Default: false
|
||||||
|
//
|
||||||
|
// disable_session_metadata false
|
||||||
|
|
||||||
|
// Enable or disable support for the enhanced Kitty Keyboard Protocol (the host terminal must also support it)
|
||||||
|
// Default: true (if the host terminal supports it)
|
||||||
|
//
|
||||||
|
// support_kitty_keyboard_protocol false
|
||||||
|
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 4182
|
||||||
|
expression: fake_document.to_string()
|
||||||
|
---
|
||||||
|
simplified_ui true
|
||||||
|
theme "dracula"
|
||||||
|
default_mode "locked"
|
||||||
|
default_shell "fish"
|
||||||
|
default_cwd "/tmp/foo"
|
||||||
|
default_layout "compact"
|
||||||
|
layout_dir "/tmp/layouts"
|
||||||
|
theme_dir "/tmp/themes"
|
||||||
|
mouse_mode false
|
||||||
|
pane_frames false
|
||||||
|
mirror_session true
|
||||||
|
on_force_close "quit"
|
||||||
|
scroll_buffer_size 100
|
||||||
|
copy_command "pbcopy"
|
||||||
|
copy_clipboard "system"
|
||||||
|
copy_on_select false
|
||||||
|
scrollback_editor "vim"
|
||||||
|
session_name "my_cool_session"
|
||||||
|
attach_to_session false
|
||||||
|
auto_layout false
|
||||||
|
session_serialization true
|
||||||
|
serialize_pane_viewport false
|
||||||
|
scrollback_lines_to_serialize 1000
|
||||||
|
styled_underlines false
|
||||||
|
serialization_interval 1
|
||||||
|
disable_session_metadata true
|
||||||
|
support_kitty_keyboard_protocol false
|
||||||
|
|
||||||
|
|
@ -0,0 +1,175 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 4987
|
||||||
|
expression: fake_document.to_string()
|
||||||
|
---
|
||||||
|
|
||||||
|
// Use a simplified UI without special fonts (arrow glyphs)
|
||||||
|
// Options:
|
||||||
|
// - true
|
||||||
|
// - false (Default)
|
||||||
|
//
|
||||||
|
simplified_ui true
|
||||||
|
|
||||||
|
// Choose the theme that is specified in the themes section.
|
||||||
|
// Default: default
|
||||||
|
//
|
||||||
|
theme "dracula"
|
||||||
|
|
||||||
|
// Choose the base input mode of zellij.
|
||||||
|
// Default: normal
|
||||||
|
//
|
||||||
|
default_mode "locked"
|
||||||
|
|
||||||
|
// Choose the path to the default shell that zellij will use for opening new panes
|
||||||
|
// Default: $SHELL
|
||||||
|
//
|
||||||
|
default_shell "fish"
|
||||||
|
|
||||||
|
// Choose the path to override cwd that zellij will use for opening new panes
|
||||||
|
//
|
||||||
|
default_cwd "/tmp/foo"
|
||||||
|
|
||||||
|
// The name of the default layout to load on startup
|
||||||
|
// Default: "default"
|
||||||
|
//
|
||||||
|
default_layout "compact"
|
||||||
|
|
||||||
|
// The folder in which Zellij will look for layouts
|
||||||
|
//
|
||||||
|
layout_dir "/tmp/layouts"
|
||||||
|
|
||||||
|
// The folder in which Zellij will look for themes
|
||||||
|
//
|
||||||
|
theme_dir "/tmp/themes"
|
||||||
|
|
||||||
|
// Toggle enabling the mouse mode.
|
||||||
|
// On certain configurations, or terminals this could
|
||||||
|
// potentially interfere with copying text.
|
||||||
|
// Options:
|
||||||
|
// - true (default)
|
||||||
|
// - false
|
||||||
|
//
|
||||||
|
mouse_mode false
|
||||||
|
|
||||||
|
// Toggle having pane frames around the panes
|
||||||
|
// Options:
|
||||||
|
// - true (default, enabled)
|
||||||
|
// - false
|
||||||
|
//
|
||||||
|
pane_frames false
|
||||||
|
|
||||||
|
// When attaching to an existing session with other users,
|
||||||
|
// should the session be mirrored (true)
|
||||||
|
// or should each user have their own cursor (false)
|
||||||
|
// Default: false
|
||||||
|
//
|
||||||
|
mirror_session true
|
||||||
|
|
||||||
|
// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP
|
||||||
|
// eg. when terminal window with an active zellij session is closed
|
||||||
|
// Options:
|
||||||
|
// - detach (Default)
|
||||||
|
// - quit
|
||||||
|
//
|
||||||
|
on_force_close "quit"
|
||||||
|
|
||||||
|
// Configure the scroll back buffer size
|
||||||
|
// This is the number of lines zellij stores for each pane in the scroll back
|
||||||
|
// buffer. Excess number of lines are discarded in a FIFO fashion.
|
||||||
|
// Valid values: positive integers
|
||||||
|
// Default value: 10000
|
||||||
|
//
|
||||||
|
scroll_buffer_size 100
|
||||||
|
|
||||||
|
// Provide a command to execute when copying text. The text will be piped to
|
||||||
|
// the stdin of the program to perform the copy. This can be used with
|
||||||
|
// terminal emulators which do not support the OSC 52 ANSI control sequence
|
||||||
|
// that will be used by default if this option is not set.
|
||||||
|
// Examples:
|
||||||
|
//
|
||||||
|
// copy_command "xclip -selection clipboard" // x11
|
||||||
|
// copy_command "wl-copy" // wayland
|
||||||
|
// copy_command "pbcopy" // osx
|
||||||
|
//
|
||||||
|
copy_command "pbcopy"
|
||||||
|
|
||||||
|
// Choose the destination for copied text
|
||||||
|
// Allows using the primary selection buffer (on x11/wayland) instead of the system clipboard.
|
||||||
|
// Does not apply when using copy_command.
|
||||||
|
// Options:
|
||||||
|
// - system (default)
|
||||||
|
// - primary
|
||||||
|
//
|
||||||
|
copy_clipboard "system"
|
||||||
|
|
||||||
|
// Enable automatic copying (and clearing) of selection when releasing mouse
|
||||||
|
// Default: true
|
||||||
|
//
|
||||||
|
copy_on_select false
|
||||||
|
|
||||||
|
// Path to the default editor to use to edit pane scrollbuffer
|
||||||
|
// Default: $EDITOR or $VISUAL
|
||||||
|
scrollback_editor "vim"
|
||||||
|
|
||||||
|
// A fixed name to always give the Zellij session.
|
||||||
|
// Consider also setting `attach_to_session true,`
|
||||||
|
// otherwise this will error if such a session exists.
|
||||||
|
// Default: <RANDOM>
|
||||||
|
//
|
||||||
|
session_name "my_cool_session"
|
||||||
|
|
||||||
|
// When `session_name` is provided, attaches to that session
|
||||||
|
// if it is already running or creates it otherwise.
|
||||||
|
// Default: false
|
||||||
|
//
|
||||||
|
attach_to_session false
|
||||||
|
|
||||||
|
// Toggle between having Zellij lay out panes according to a predefined set of layouts whenever possible
|
||||||
|
// Options:
|
||||||
|
// - true (default)
|
||||||
|
// - false
|
||||||
|
//
|
||||||
|
auto_layout false
|
||||||
|
|
||||||
|
// Whether sessions should be serialized to the cache folder (including their tabs/panes, cwds and running commands) so that they can later be resurrected
|
||||||
|
// Options:
|
||||||
|
// - true (default)
|
||||||
|
// - false
|
||||||
|
//
|
||||||
|
session_serialization true
|
||||||
|
|
||||||
|
// Whether pane viewports are serialized along with the session, default is false
|
||||||
|
// Options:
|
||||||
|
// - true
|
||||||
|
// - false (default)
|
||||||
|
//
|
||||||
|
serialize_pane_viewport false
|
||||||
|
|
||||||
|
// Scrollback lines to serialize along with the pane viewport when serializing sessions, 0
|
||||||
|
// defaults to the scrollback size. If this number is higher than the scrollback size, it will
|
||||||
|
// also default to the scrollback size. This does nothing if `serialize_pane_viewport` is not true.
|
||||||
|
//
|
||||||
|
scrollback_lines_to_serialize 1000
|
||||||
|
|
||||||
|
// Enable or disable the rendering of styled and colored underlines (undercurl).
|
||||||
|
// May need to be disabled for certain unsupported terminals
|
||||||
|
// Default: true
|
||||||
|
//
|
||||||
|
styled_underlines false
|
||||||
|
|
||||||
|
// How often in seconds sessions are serialized
|
||||||
|
//
|
||||||
|
serialization_interval 1
|
||||||
|
|
||||||
|
// Enable or disable writing of session metadata to disk (if disabled, other sessions might not know
|
||||||
|
// metadata info on this session)
|
||||||
|
// Default: false
|
||||||
|
//
|
||||||
|
disable_session_metadata true
|
||||||
|
|
||||||
|
// Enable or disable support for the enhanced Kitty Keyboard Protocol (the host terminal must also support it)
|
||||||
|
// Default: true (if the host terminal supports it)
|
||||||
|
//
|
||||||
|
support_kitty_keyboard_protocol false
|
||||||
|
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 4211
|
||||||
|
expression: fake_document.to_string()
|
||||||
|
---
|
||||||
|
default_layout "compact"
|
||||||
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 4196
|
||||||
|
expression: fake_document.to_string()
|
||||||
|
---
|
||||||
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 3981
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
env {
|
||||||
|
bar "foo"
|
||||||
|
baz "true"
|
||||||
|
foo "bar"
|
||||||
|
thing "1"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 2558
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
keybinds clear-defaults=true {
|
||||||
|
normal {
|
||||||
|
bind "Ctrl g" { SwitchToMode "locked"; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,130 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 2731
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
keybinds clear-defaults=true {
|
||||||
|
normal {
|
||||||
|
bind "Ctrl a" { Quit; }
|
||||||
|
bind "Ctrl Alt a" { Search "up"; }
|
||||||
|
bind "Alt a" { ToggleActiveSyncTab; }
|
||||||
|
bind "Ctrl b" { Write 102 111 111; }
|
||||||
|
bind "Ctrl Alt b" { SearchToggleOption "CaseSensitivity"; }
|
||||||
|
bind "Alt b" { NewPane "right"; }
|
||||||
|
bind "Ctrl c" { WriteChars "hi there!"; }
|
||||||
|
bind "Ctrl Alt c" { ToggleMouseMode; }
|
||||||
|
bind "Alt c" { TogglePaneEmbedOrFloating; }
|
||||||
|
bind "Ctrl d" { SwitchToMode "locked"; }
|
||||||
|
bind "Ctrl Alt d" { PreviousSwapLayout; }
|
||||||
|
bind "Alt d" { ToggleFloatingPanes; }
|
||||||
|
bind "Ctrl e" { Resize "Increase"; }
|
||||||
|
bind "Ctrl Alt e" { NextSwapLayout; }
|
||||||
|
bind "Alt e" { CloseFocus; }
|
||||||
|
bind "Ctrl f" { FocusNextPane; }
|
||||||
|
bind "Alt f" { PaneNameInput 0; }
|
||||||
|
bind "Ctrl g" { FocusPreviousPane; }
|
||||||
|
bind "Ctrl Alt g" { BreakPane; }
|
||||||
|
bind "Alt g" { UndoRenamePane; }
|
||||||
|
bind "Ctrl h" { SwitchFocus; }
|
||||||
|
bind "Ctrl Alt h" { BreakPaneRight; }
|
||||||
|
bind "Alt h" { NewTab; }
|
||||||
|
bind "Ctrl i" { MoveFocus "right"; }
|
||||||
|
bind "Ctrl Alt i" { BreakPaneLeft; }
|
||||||
|
bind "Alt i" { GoToNextTab; }
|
||||||
|
bind "Ctrl j" { MoveFocusOrTab "right"; }
|
||||||
|
bind "Ctrl Alt j" {
|
||||||
|
MessagePlugin "zellij:session-manager" {
|
||||||
|
name "message_name"
|
||||||
|
cwd "/tmp"
|
||||||
|
payload "message_payload"
|
||||||
|
launch_new true
|
||||||
|
skip_cache true
|
||||||
|
floating true
|
||||||
|
title "plugin_title"
|
||||||
|
config_key_1 "config_value_1"
|
||||||
|
config_key_2 "config_value_2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bind "Alt j" { GoToPreviousTab; }
|
||||||
|
bind "Ctrl k" { MovePane "right"; }
|
||||||
|
bind "Alt k" { CloseTab; }
|
||||||
|
bind "Ctrl l" { MovePaneBackwards; }
|
||||||
|
bind "Alt l" { GoToTab 1; }
|
||||||
|
bind "Ctrl m" { Resize "Decrease down"; }
|
||||||
|
bind "Alt m" { ToggleTab; }
|
||||||
|
bind "Ctrl n" { DumpScreen "/tmp/dumped"; }
|
||||||
|
bind "Alt n" { TabNameInput 0; }
|
||||||
|
bind "Ctrl o" { DumpLayout; }
|
||||||
|
bind "Alt o" { UndoRenameTab; }
|
||||||
|
bind "Ctrl p" { EditScrollback; }
|
||||||
|
bind "Alt p" { MoveTab "right"; }
|
||||||
|
bind "Ctrl q" { ScrollUp; }
|
||||||
|
bind "Alt q" {
|
||||||
|
Run "ls" "-l" {
|
||||||
|
cwd "/tmp"
|
||||||
|
name "my cool pane"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bind "Ctrl r" { ScrollDown; }
|
||||||
|
bind "Alt r" {
|
||||||
|
Run "ls" "-l" {
|
||||||
|
floating true
|
||||||
|
cwd "/tmp"
|
||||||
|
name "my cool pane"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bind "Ctrl s" { ScrollToBottom; }
|
||||||
|
bind "Alt s" {
|
||||||
|
Run "ls" "-l" {
|
||||||
|
in_place true
|
||||||
|
cwd "/tmp"
|
||||||
|
name "my cool pane"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bind "Ctrl t" { ScrollToTop; }
|
||||||
|
bind "Alt t" { Detach; }
|
||||||
|
bind "Ctrl u" { PageScrollUp; }
|
||||||
|
bind "Alt u" {
|
||||||
|
LaunchOrFocusPlugin "zellij:session-manager" {
|
||||||
|
floating true
|
||||||
|
move_to_focused_tab true
|
||||||
|
skip_plugin_cache true
|
||||||
|
config_key_1 "config_value_1"
|
||||||
|
config_key_2 "config_value_2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bind "Ctrl v" { PageScrollDown; }
|
||||||
|
bind "Alt v" {
|
||||||
|
LaunchOrFocusPlugin "zellij:session-manager" {
|
||||||
|
move_to_focused_tab true
|
||||||
|
in_place true
|
||||||
|
skip_plugin_cache true
|
||||||
|
config_key_1 "config_value_1"
|
||||||
|
config_key_2 "config_value_2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bind "Ctrl w" { HalfPageScrollUp; }
|
||||||
|
bind "Alt w" {
|
||||||
|
LaunchPlugin "zellij:session-manager" {
|
||||||
|
floating true
|
||||||
|
skip_plugin_cache true
|
||||||
|
config_key_1 "config_value_1"
|
||||||
|
config_key_2 "config_value_2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bind "Ctrl x" { HalfPageScrollDown; }
|
||||||
|
bind "Alt x" {
|
||||||
|
LaunchPlugin "zellij:session-manager" {
|
||||||
|
in_place true
|
||||||
|
skip_plugin_cache true
|
||||||
|
config_key_1 "config_value_1"
|
||||||
|
config_key_2 "config_value_2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bind "Ctrl y" { ToggleFocusFullscreen; }
|
||||||
|
bind "Alt y" { Copy; }
|
||||||
|
bind "Ctrl z" { TogglePaneFrames; }
|
||||||
|
bind "Alt z" { SearchInput 0; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 2576
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
keybinds clear-defaults=true {
|
||||||
|
normal {
|
||||||
|
bind "Ctrl n" { NewPane; SwitchToMode "locked"; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 2788
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
keybinds clear-defaults=true {
|
||||||
|
shared {
|
||||||
|
bind "Ctrl n" {
|
||||||
|
NewPane
|
||||||
|
SwitchToMode "locked"
|
||||||
|
MessagePlugin "zellij:session-manager" {
|
||||||
|
name "message_name"
|
||||||
|
cwd "/tmp"
|
||||||
|
payload "message_payload"
|
||||||
|
launch_new true
|
||||||
|
skip_cache true
|
||||||
|
floating true
|
||||||
|
title "plugin_title"
|
||||||
|
config_key_1 "config_value_1"
|
||||||
|
config_key_2 "config_value_2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 2757
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
keybinds clear-defaults=true {
|
||||||
|
shared_among "normal" "locked" {
|
||||||
|
bind "Ctrl n" { NewPane; SwitchToMode "locked"; }
|
||||||
|
}
|
||||||
|
shared_except "locked" "pane" {
|
||||||
|
bind "Ctrl f" { TogglePaneEmbedOrFloating; }
|
||||||
|
}
|
||||||
|
shared_among "locked" "pane" {
|
||||||
|
bind "Ctrl p" { WriteChars "foo"; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 2575
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
keybinds {
|
||||||
|
normal {
|
||||||
|
bind "Ctrl g" { SwitchToMode "locked"; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 3874
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
plugins {
|
||||||
|
compact-bar location="zellij:compact-bar"
|
||||||
|
filepicker location="zellij:strider" {
|
||||||
|
cwd "/"
|
||||||
|
}
|
||||||
|
session-manager location="zellij:session-manager"
|
||||||
|
status-bar location="zellij:status-bar"
|
||||||
|
strider location="zellij:strider"
|
||||||
|
tab-bar location="zellij:tab-bar"
|
||||||
|
welcome-screen location="zellij:session-manager" {
|
||||||
|
welcome_screen true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 3891
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
plugins {
|
||||||
|
filepicker location="file:/path/to/my/plugin.wasm" {
|
||||||
|
cwd "/"
|
||||||
|
}
|
||||||
|
tab-bar location="https://foo.com/plugin.wasm"
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 3697
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
themes {
|
||||||
|
dracula {
|
||||||
|
fg 248 248 242
|
||||||
|
bg 40 42 54
|
||||||
|
red 255 85 85
|
||||||
|
green 80 250 123
|
||||||
|
yellow 241 250 140
|
||||||
|
blue 98 114 164
|
||||||
|
magenta 255 121 198
|
||||||
|
orange 255 184 108
|
||||||
|
cyan 139 233 253
|
||||||
|
black 0 0 0
|
||||||
|
white 255 255 255
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 3775
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
themes {
|
||||||
|
default {
|
||||||
|
fg 1
|
||||||
|
bg 10
|
||||||
|
red 30
|
||||||
|
green 40
|
||||||
|
yellow 50
|
||||||
|
blue 60
|
||||||
|
magenta 70
|
||||||
|
orange 208 135 112
|
||||||
|
cyan 80
|
||||||
|
black 20
|
||||||
|
white 255 255 255
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 3749
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
themes {
|
||||||
|
default {
|
||||||
|
fg 1
|
||||||
|
bg 10
|
||||||
|
red 30
|
||||||
|
green 40
|
||||||
|
yellow 50
|
||||||
|
blue 60
|
||||||
|
magenta 70
|
||||||
|
orange 254
|
||||||
|
cyan 80
|
||||||
|
black 20
|
||||||
|
white 90
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 3723
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
themes {
|
||||||
|
nord {
|
||||||
|
fg 216 222 233
|
||||||
|
bg 46 52 64
|
||||||
|
red 191 97 106
|
||||||
|
green 163 190 140
|
||||||
|
yellow 235 203 139
|
||||||
|
blue 129 161 193
|
||||||
|
magenta 180 142 173
|
||||||
|
orange 208 135 112
|
||||||
|
cyan 136 192 208
|
||||||
|
black 59 66 82
|
||||||
|
white 229 233 240
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 4821
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
themes {
|
||||||
|
dracula {
|
||||||
|
fg 248 248 242
|
||||||
|
bg 40 42 54
|
||||||
|
red 255 85 85
|
||||||
|
green 80 250 123
|
||||||
|
yellow 241 250 140
|
||||||
|
blue 98 114 164
|
||||||
|
magenta 255 121 198
|
||||||
|
orange 255 184 108
|
||||||
|
cyan 139 233 253
|
||||||
|
black 0 0 0
|
||||||
|
white 255 255 255
|
||||||
|
}
|
||||||
|
nord {
|
||||||
|
fg 216 222 233
|
||||||
|
bg 46 52 64
|
||||||
|
red 191 97 106
|
||||||
|
green 163 190 140
|
||||||
|
yellow 235 203 139
|
||||||
|
blue 129 161 193
|
||||||
|
magenta 180 142 173
|
||||||
|
orange 208 135 112
|
||||||
|
cyan 136 192 208
|
||||||
|
black 59 66 82
|
||||||
|
white 229 233 240
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
---
|
||||||
|
source: zellij-utils/src/kdl/mod.rs
|
||||||
|
assertion_line: 3932
|
||||||
|
expression: serialized.to_string()
|
||||||
|
---
|
||||||
|
ui {
|
||||||
|
pane_frames {
|
||||||
|
rounded_corners true
|
||||||
|
hide_session_name true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -48,6 +48,7 @@ enum EventType {
|
||||||
EditPaneOpened = 22;
|
EditPaneOpened = 22;
|
||||||
EditPaneExited = 23;
|
EditPaneExited = 23;
|
||||||
CommandPaneReRun = 24;
|
CommandPaneReRun = 24;
|
||||||
|
FailedToWriteConfigToDisk = 25;
|
||||||
}
|
}
|
||||||
|
|
||||||
message EventNameList {
|
message EventNameList {
|
||||||
|
|
@ -77,9 +78,14 @@ message Event {
|
||||||
EditPaneOpenedPayload edit_pane_opened_payload = 19;
|
EditPaneOpenedPayload edit_pane_opened_payload = 19;
|
||||||
EditPaneExitedPayload edit_pane_exited_payload = 20;
|
EditPaneExitedPayload edit_pane_exited_payload = 20;
|
||||||
CommandPaneReRunPayload command_pane_rerun_payload = 21;
|
CommandPaneReRunPayload command_pane_rerun_payload = 21;
|
||||||
|
FailedToWriteConfigToDiskPayload failed_to_write_config_to_disk_payload = 22;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message FailedToWriteConfigToDiskPayload {
|
||||||
|
optional string file_path = 1;
|
||||||
|
}
|
||||||
|
|
||||||
message CommandPaneReRunPayload {
|
message CommandPaneReRunPayload {
|
||||||
uint32 terminal_pane_id = 1;
|
uint32 terminal_pane_id = 1;
|
||||||
repeated ContextItem context = 3;
|
repeated ContextItem context = 3;
|
||||||
|
|
|
||||||
|
|
@ -312,6 +312,14 @@ impl TryFrom<ProtobufEvent> for Event {
|
||||||
},
|
},
|
||||||
_ => Err("Malformed payload for the CommandPaneReRun Event"),
|
_ => Err("Malformed payload for the CommandPaneReRun Event"),
|
||||||
},
|
},
|
||||||
|
Some(ProtobufEventType::FailedToWriteConfigToDisk) => match protobuf_event.payload {
|
||||||
|
Some(ProtobufEventPayload::FailedToWriteConfigToDiskPayload(
|
||||||
|
failed_to_write_configuration_payload,
|
||||||
|
)) => Ok(Event::FailedToWriteConfigToDisk(
|
||||||
|
failed_to_write_configuration_payload.file_path,
|
||||||
|
)),
|
||||||
|
_ => Err("Malformed payload for the FailedToWriteConfigToDisk Event"),
|
||||||
|
},
|
||||||
None => Err("Unknown Protobuf Event"),
|
None => Err("Unknown Protobuf Event"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -620,6 +628,12 @@ impl TryFrom<Event> for ProtobufEvent {
|
||||||
)),
|
)),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
Event::FailedToWriteConfigToDisk(file_path) => Ok(ProtobufEvent {
|
||||||
|
name: ProtobufEventType::FailedToWriteConfigToDisk as i32,
|
||||||
|
payload: Some(event::Payload::FailedToWriteConfigToDiskPayload(
|
||||||
|
FailedToWriteConfigToDiskPayload { file_path },
|
||||||
|
)),
|
||||||
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1129,6 +1143,7 @@ impl TryFrom<ProtobufEventType> for EventType {
|
||||||
ProtobufEventType::EditPaneOpened => EventType::EditPaneOpened,
|
ProtobufEventType::EditPaneOpened => EventType::EditPaneOpened,
|
||||||
ProtobufEventType::EditPaneExited => EventType::EditPaneExited,
|
ProtobufEventType::EditPaneExited => EventType::EditPaneExited,
|
||||||
ProtobufEventType::CommandPaneReRun => EventType::CommandPaneReRun,
|
ProtobufEventType::CommandPaneReRun => EventType::CommandPaneReRun,
|
||||||
|
ProtobufEventType::FailedToWriteConfigToDisk => EventType::FailedToWriteConfigToDisk,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1162,6 +1177,7 @@ impl TryFrom<EventType> for ProtobufEventType {
|
||||||
EventType::EditPaneOpened => ProtobufEventType::EditPaneOpened,
|
EventType::EditPaneOpened => ProtobufEventType::EditPaneOpened,
|
||||||
EventType::EditPaneExited => ProtobufEventType::EditPaneExited,
|
EventType::EditPaneExited => ProtobufEventType::EditPaneExited,
|
||||||
EventType::CommandPaneReRun => ProtobufEventType::CommandPaneReRun,
|
EventType::CommandPaneReRun => ProtobufEventType::CommandPaneReRun,
|
||||||
|
EventType::FailedToWriteConfigToDisk => ProtobufEventType::FailedToWriteConfigToDisk,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ message PluginCommand {
|
||||||
KillSessionsPayload kill_sessions_payload = 60;
|
KillSessionsPayload kill_sessions_payload = 60;
|
||||||
string scan_host_folder_payload = 61;
|
string scan_host_folder_payload = 61;
|
||||||
NewTabsWithLayoutInfoPayload new_tabs_with_layout_info_payload = 62;
|
NewTabsWithLayoutInfoPayload new_tabs_with_layout_info_payload = 62;
|
||||||
string reconfigure_payload = 63;
|
ReconfigurePayload reconfigure_payload = 63;
|
||||||
HidePaneWithIdPayload hide_pane_with_id_payload = 64;
|
HidePaneWithIdPayload hide_pane_with_id_payload = 64;
|
||||||
ShowPaneWithIdPayload show_pane_with_id_payload = 65;
|
ShowPaneWithIdPayload show_pane_with_id_payload = 65;
|
||||||
OpenCommandPanePayload open_command_pane_background_payload = 66;
|
OpenCommandPanePayload open_command_pane_background_payload = 66;
|
||||||
|
|
@ -168,6 +168,11 @@ message PluginCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message ReconfigurePayload {
|
||||||
|
string config = 1;
|
||||||
|
bool write_to_disk = 2;
|
||||||
|
}
|
||||||
|
|
||||||
message RerunCommandPanePayload {
|
message RerunCommandPanePayload {
|
||||||
uint32 terminal_pane_id = 1;
|
uint32 terminal_pane_id = 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,9 +11,9 @@ pub use super::generated_api::api::{
|
||||||
MovePayload, NewPluginArgs as ProtobufNewPluginArgs, NewTabsWithLayoutInfoPayload,
|
MovePayload, NewPluginArgs as ProtobufNewPluginArgs, NewTabsWithLayoutInfoPayload,
|
||||||
OpenCommandPanePayload, OpenFilePayload, PaneId as ProtobufPaneId,
|
OpenCommandPanePayload, OpenFilePayload, PaneId as ProtobufPaneId,
|
||||||
PaneType as ProtobufPaneType, PluginCommand as ProtobufPluginCommand, PluginMessagePayload,
|
PaneType as ProtobufPaneType, PluginCommand as ProtobufPluginCommand, PluginMessagePayload,
|
||||||
RequestPluginPermissionPayload, RerunCommandPanePayload, ResizePayload, RunCommandPayload,
|
ReconfigurePayload, RequestPluginPermissionPayload, RerunCommandPanePayload, ResizePayload,
|
||||||
SetTimeoutPayload, ShowPaneWithIdPayload, SubscribePayload, SwitchSessionPayload,
|
RunCommandPayload, SetTimeoutPayload, ShowPaneWithIdPayload, SubscribePayload,
|
||||||
SwitchTabToPayload, UnsubscribePayload, WebRequestPayload,
|
SwitchSessionPayload, SwitchTabToPayload, UnsubscribePayload, WebRequestPayload,
|
||||||
},
|
},
|
||||||
plugin_permission::PermissionType as ProtobufPermissionType,
|
plugin_permission::PermissionType as ProtobufPermissionType,
|
||||||
resize::ResizeAction as ProtobufResizeAction,
|
resize::ResizeAction as ProtobufResizeAction,
|
||||||
|
|
@ -935,7 +935,10 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
|
||||||
},
|
},
|
||||||
Some(CommandName::Reconfigure) => match protobuf_plugin_command.payload {
|
Some(CommandName::Reconfigure) => match protobuf_plugin_command.payload {
|
||||||
Some(Payload::ReconfigurePayload(reconfigure_payload)) => {
|
Some(Payload::ReconfigurePayload(reconfigure_payload)) => {
|
||||||
Ok(PluginCommand::Reconfigure(reconfigure_payload))
|
Ok(PluginCommand::Reconfigure(
|
||||||
|
reconfigure_payload.config,
|
||||||
|
reconfigure_payload.write_to_disk,
|
||||||
|
))
|
||||||
},
|
},
|
||||||
_ => Err("Mismatched payload for Reconfigure"),
|
_ => Err("Mismatched payload for Reconfigure"),
|
||||||
},
|
},
|
||||||
|
|
@ -1558,9 +1561,12 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
|
||||||
)),
|
)),
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
PluginCommand::Reconfigure(reconfigure_payload) => Ok(ProtobufPluginCommand {
|
PluginCommand::Reconfigure(config, write_to_disk) => Ok(ProtobufPluginCommand {
|
||||||
name: CommandName::Reconfigure as i32,
|
name: CommandName::Reconfigure as i32,
|
||||||
payload: Some(Payload::ReconfigurePayload(reconfigure_payload)),
|
payload: Some(Payload::ReconfigurePayload(ReconfigurePayload {
|
||||||
|
config,
|
||||||
|
write_to_disk,
|
||||||
|
})),
|
||||||
}),
|
}),
|
||||||
PluginCommand::HidePaneWithId(pane_id_to_hide) => Ok(ProtobufPluginCommand {
|
PluginCommand::HidePaneWithId(pane_id_to_hide) => Ok(ProtobufPluginCommand {
|
||||||
name: CommandName::HidePaneWithId as i32,
|
name: CommandName::HidePaneWithId as i32,
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,8 @@ fn get_default_themes() -> Themes {
|
||||||
let mut themes = Themes::default();
|
let mut themes = Themes::default();
|
||||||
for file in ZELLIJ_DEFAULT_THEMES.files() {
|
for file in ZELLIJ_DEFAULT_THEMES.files() {
|
||||||
if let Some(content) = file.contents_utf8() {
|
if let Some(content) = file.contents_utf8() {
|
||||||
match Themes::from_string(&content.to_string()) {
|
let sourced_from_external_file = true;
|
||||||
|
match Themes::from_string(&content.to_string(), sourced_from_external_file) {
|
||||||
Ok(theme) => themes = themes.merge(theme),
|
Ok(theme) => themes = themes.merge(theme),
|
||||||
Err(_) => {},
|
Err(_) => {},
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
source: zellij-utils/src/setup.rs
|
source: zellij-utils/src/setup.rs
|
||||||
assertion_line: 839
|
assertion_line: 840
|
||||||
expression: "format!(\"{:#?}\", config)"
|
expression: "format!(\"{:#?}\", config)"
|
||||||
---
|
---
|
||||||
Config {
|
Config {
|
||||||
|
|
@ -5671,6 +5671,7 @@ Config {
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
sourced_from_external_file: false,
|
||||||
},
|
},
|
||||||
"theme-from-config": Theme {
|
"theme-from-config": Theme {
|
||||||
palette: Palette {
|
palette: Palette {
|
||||||
|
|
@ -5772,6 +5773,7 @@ Config {
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
sourced_from_external_file: false,
|
||||||
},
|
},
|
||||||
"theme-from-layout": Theme {
|
"theme-from-layout": Theme {
|
||||||
palette: Palette {
|
palette: Palette {
|
||||||
|
|
@ -5873,6 +5875,7 @@ Config {
|
||||||
0,
|
0,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
sourced_from_external_file: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: PluginAliases {
|
plugins: PluginAliases {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue