feat(ui): configuration screen + configure non-colliding keys at runtime (#3502)

* rebind => reconfigure

* persist keybinds and mode info to new tabs

* add configuration plugin

* make tests pass

* remove warnings

* style(fmt): rustfmt
This commit is contained in:
Aram Drevekenin 2024-07-17 16:08:31 +02:00 committed by GitHub
parent f6ec1a1385
commit 84ff29dd02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 3066 additions and 95 deletions

9
Cargo.lock generated
View file

@ -749,6 +749,15 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "configuration"
version = "0.1.0"
dependencies = [
"ansi_term",
"chrono",
"zellij-tile",
]
[[package]] [[package]]
name = "console" name = "console"
version = "0.15.0" version = "0.15.0"

View file

@ -37,6 +37,7 @@ members = [
"default-plugins/tab-bar", "default-plugins/tab-bar",
"default-plugins/fixture-plugin-for-tests", "default-plugins/fixture-plugin-for-tests",
"default-plugins/session-manager", "default-plugins/session-manager",
"default-plugins/configuration",
"zellij-client", "zellij-client",
"zellij-server", "zellij-server",
"zellij-utils", "zellij-utils",

View file

@ -0,0 +1,2 @@
[build]
target = "wasm32-wasi"

View file

@ -0,0 +1 @@
/target

View file

@ -0,0 +1,11 @@
[package]
name = "configuration"
version = "0.1.0"
authors = ["Aram Drevekenin <aram@poor.dev>"]
edition = "2021"
license = "MIT"
[dependencies]
ansi_term = "0.12.1"
zellij-tile = { path = "../../zellij-tile" }
chrono = "0.4.0"

View file

@ -0,0 +1 @@
../../LICENSE.md

File diff suppressed because it is too large Load diff

View file

@ -56,7 +56,7 @@ impl ZellijPlugin for State {
PermissionType::WebAccess, PermissionType::WebAccess,
PermissionType::ReadCliPipes, PermissionType::ReadCliPipes,
PermissionType::MessageAndLaunchOtherPlugins, PermissionType::MessageAndLaunchOtherPlugins,
PermissionType::RebindKeys, PermissionType::Reconfigure,
]); ]);
self.configuration = configuration; self.configuration = configuration;
subscribe(&[ subscribe(&[
@ -320,7 +320,7 @@ impl ZellijPlugin for State {
); );
}, },
BareKey::Char('0') if key.has_modifiers(&[KeyModifier::Ctrl]) => { BareKey::Char('0') if key.has_modifiers(&[KeyModifier::Ctrl]) => {
rebind_keys( reconfigure(
" "
keybinds { keybinds {
locked { locked {

View file

@ -1265,6 +1265,7 @@ fn get_keys_and_hints(mi: &ModeInfo) -> Vec<(String, String, Vec<KeyWithModifier
]} else if mi.mode == IM::Session { vec![ ]} else if mi.mode == IM::Session { vec![
(s("Detach"), s("Detach"), action_key(&km, &[Action::Detach])), (s("Detach"), s("Detach"), action_key(&km, &[Action::Detach])),
(s("Session Manager"), s("Manager"), session_manager_key(&km)), (s("Session Manager"), s("Manager"), session_manager_key(&km)),
(s("Configure"), s("Config"), configuration_key(&km)),
(s("Select pane"), s("Select"), to_basemode_key), (s("Select pane"), s("Select"), to_basemode_key),
]} else if mi.mode == IM::Tmux { vec![ ]} else if mi.mode == IM::Tmux { vec![
(s("Move focus"), s("Move"), action_key_group(&km, &[ (s("Move focus"), s("Move"), action_key_group(&km, &[
@ -1355,6 +1356,25 @@ fn session_manager_key(keymap: &[(KeyWithModifier, Vec<Action>)]) -> Vec<KeyWith
} }
} }
fn configuration_key(keymap: &[(KeyWithModifier, Vec<Action>)]) -> Vec<KeyWithModifier> {
let mut matching = keymap.iter().find_map(|(key, acvec)| {
let has_match = acvec
.iter()
.find(|a| a.launches_plugin("configuration"))
.is_some();
if has_match {
Some(key.clone())
} else {
None
}
});
if let Some(matching) = matching.take() {
vec![matching]
} else {
vec![]
}
}
fn style_key_with_modifier(keyvec: &[KeyWithModifier], color_index: Option<usize>) -> LinePart { fn style_key_with_modifier(keyvec: &[KeyWithModifier], color_index: Option<usize>) -> LinePart {
if keyvec.is_empty() { if keyvec.is_empty() {
return LinePart::default(); return LinePart::default();

View file

@ -1,6 +1,6 @@
--- ---
source: src/tests/e2e/cases.rs source: src/tests/e2e/cases.rs
assertion_line: 1050 assertion_line: 1064
expression: last_snapshot expression: last_snapshot
--- ---
Zellij (e2e-test)  Tab #1  Zellij (e2e-test)  Tab #1 
@ -26,4 +26,4 @@ expression: last_snapshot
│ ││ │ │ ││ │
│ ││ │ │ ││ │
└────────────────────────────────────────────────┘└────────────────────────────────────────────────┘ └────────────────────────────────────────────────┘└────────────────────────────────────────────────┘
Ctrl + g  p  t  n  h  s  o  q  Alt +  <n> New Pane  <←↓↑→> Change Focus Ctrl + g  p  t  n  h  s  o  q  Alt +  <n> New  <←↓↑→> Focus  <f> Floating

View file

@ -1,6 +1,6 @@
--- ---
source: src/tests/e2e/cases.rs source: src/tests/e2e/cases.rs
assertion_line: 2349 assertion_line: 2372
expression: last_snapshot expression: last_snapshot
--- ---
Zellij (e2e-test)  Tab #1  Alt <[]>  VERTICAL  Zellij (e2e-test)  Tab #1  Alt <[]>  VERTICAL 
@ -26,4 +26,4 @@ expression: last_snapshot
│ ││ │ │ ││ │
│ ││ │ │ ││ │
└─────────────────────────────────────────────────────────────────────────┘└ [ EXIT CODE: 0 ] <ENTER> re-run, <ESC> drop to shell, <Ctrl-c> exit ────┘ └─────────────────────────────────────────────────────────────────────────┘└ [ EXIT CODE: 0 ] <ENTER> re-run, <ESC> drop to shell, <Ctrl-c> exit ────┘
Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT  Alt +  <n> New  <←↓↑→> Focus  Ctrl + <g> LOCK  <p> PANE  <t> TAB  <n> RESIZE  <h> MOVE  <s> SEARCH  <o> SESSION  <q> QUIT 

View file

@ -36,6 +36,7 @@ lazy_static::lazy_static! {
WorkspaceMember{crate_name: "default-plugins/tab-bar", build: true}, WorkspaceMember{crate_name: "default-plugins/tab-bar", build: true},
WorkspaceMember{crate_name: "default-plugins/fixture-plugin-for-tests", build: true}, WorkspaceMember{crate_name: "default-plugins/fixture-plugin-for-tests", build: true},
WorkspaceMember{crate_name: "default-plugins/session-manager", build: true}, WorkspaceMember{crate_name: "default-plugins/session-manager", build: true},
WorkspaceMember{crate_name: "default-plugins/configuration", build: true},
WorkspaceMember{crate_name: "zellij-utils", build: false}, WorkspaceMember{crate_name: "zellij-utils", build: false},
WorkspaceMember{crate_name: "zellij-tile-utils", build: false}, WorkspaceMember{crate_name: "zellij-tile-utils", build: false},
WorkspaceMember{crate_name: "zellij-tile", build: false}, WorkspaceMember{crate_name: "zellij-tile", build: false},

View file

@ -97,7 +97,7 @@ pub enum ServerInstruction {
DisconnectAllClientsExcept(ClientId), DisconnectAllClientsExcept(ClientId),
ChangeMode(ClientId, InputMode), ChangeMode(ClientId, InputMode),
ChangeModeForAllClients(InputMode), ChangeModeForAllClients(InputMode),
RebindKeys(ClientId, String), // String -> stringified keybindings Reconfigure(ClientId, String), // String -> stringified configuration
} }
impl From<&ServerInstruction> for ServerContext { impl From<&ServerInstruction> for ServerContext {
@ -129,7 +129,7 @@ impl From<&ServerInstruction> for ServerContext {
ServerInstruction::ChangeModeForAllClients(..) => { ServerInstruction::ChangeModeForAllClients(..) => {
ServerContext::ChangeModeForAllClients ServerContext::ChangeModeForAllClients
}, },
ServerInstruction::RebindKeys(..) => ServerContext::RebindKeys, ServerInstruction::Reconfigure(..) => ServerContext::Reconfigure,
} }
} }
} }
@ -149,7 +149,7 @@ pub(crate) struct SessionMetaData {
pub config_options: Box<Options>, pub config_options: Box<Options>,
pub client_keybinds: HashMap<ClientId, Keybinds>, pub client_keybinds: HashMap<ClientId, Keybinds>,
pub client_input_modes: HashMap<ClientId, InputMode>, pub client_input_modes: HashMap<ClientId, InputMode>,
pub default_mode: 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<()>>,
@ -570,6 +570,10 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
default_mode, default_mode,
&attrs, &attrs,
session_data.capabilities, session_data.capabilities,
session_data
.client_keybinds
.get(&client_id)
.unwrap_or(&session_data.client_attributes.keybinds),
Some(default_mode), Some(default_mode),
); );
session_data session_data
@ -911,24 +915,57 @@ 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::RebindKeys(client_id, new_keybinds) => { ServerInstruction::Reconfigure(client_id, new_config) => {
let mut new_default_mode = None;
match Options::from_string(&new_config) {
Ok(mut new_config_options) => {
if let Some(default_mode) = new_config_options.default_mode.take() {
new_default_mode = Some(default_mode);
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 let new_keybinds = session_data
.write() .write()
.unwrap() .unwrap()
.as_mut() .as_mut()
.unwrap() .unwrap()
.rebind_keys(client_id, new_keybinds) .rebind_keys(client_id, new_config)
.clone(); .clone();
if let Some(new_keybinds) = new_keybinds { session_data
session_data .write()
.write() .unwrap()
.unwrap() .as_ref()
.as_ref() .unwrap()
.unwrap() .senders
.senders .send_to_screen(ScreenInstruction::Reconfigure {
.send_to_screen(ScreenInstruction::RebindKeys(new_keybinds, client_id)) client_id,
.unwrap(); 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();
}, },
} }
} }
@ -1167,7 +1204,7 @@ fn init_session(
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, default_mode: HashMap::new(),
} }
} }

View file

@ -31,6 +31,7 @@ use zellij_utils::{
errors::{prelude::*, ContextType, PluginContext}, errors::{prelude::*, ContextType, PluginContext},
input::{ input::{
command::TerminalAction, command::TerminalAction,
keybinds::Keybinds,
layout::{FloatingPaneLayout, Layout, Run, RunPlugin, RunPluginOrAlias, TiledPaneLayout}, layout::{FloatingPaneLayout, Layout, Run, RunPlugin, RunPluginOrAlias, TiledPaneLayout},
plugins::PluginAliases, plugins::PluginAliases,
}, },
@ -142,6 +143,11 @@ pub enum PluginInstruction {
message: MessageToPlugin, message: MessageToPlugin,
}, },
UnblockCliPipes(Vec<PluginRenderAsset>), UnblockCliPipes(Vec<PluginRenderAsset>),
Reconfigure {
client_id: ClientId,
keybinds: Option<Keybinds>,
default_mode: Option<InputMode>,
},
WatchFilesystem, WatchFilesystem,
Exit, Exit,
} }
@ -182,6 +188,7 @@ impl From<&PluginInstruction> for PluginContext {
PluginInstruction::WatchFilesystem => PluginContext::WatchFilesystem, PluginInstruction::WatchFilesystem => PluginContext::WatchFilesystem,
PluginInstruction::KeybindPipe { .. } => PluginContext::KeybindPipe, PluginInstruction::KeybindPipe { .. } => PluginContext::KeybindPipe,
PluginInstruction::DumpLayoutToPlugin(..) => PluginContext::DumpLayoutToPlugin, PluginInstruction::DumpLayoutToPlugin(..) => PluginContext::DumpLayoutToPlugin,
PluginInstruction::Reconfigure { .. } => PluginContext::Reconfigure,
} }
} }
} }
@ -734,6 +741,15 @@ pub(crate) fn plugin_thread_main(
.context("failed to unblock input pipe"); .context("failed to unblock input pipe");
} }
}, },
PluginInstruction::Reconfigure {
client_id,
keybinds,
default_mode,
} => {
wasm_bridge
.reconfigure(client_id, keybinds, default_mode)
.non_fatal();
},
PluginInstruction::WatchFilesystem => { PluginInstruction::WatchFilesystem => {
wasm_bridge.start_fs_watcher_if_not_started(); wasm_bridge.start_fs_watcher_if_not_started();
}, },

View file

@ -29,6 +29,7 @@ use zellij_utils::{
data::{InputMode, PluginCapabilities}, data::{InputMode, PluginCapabilities},
errors::prelude::*, errors::prelude::*,
input::command::TerminalAction, input::command::TerminalAction,
input::keybinds::Keybinds,
input::layout::Layout, input::layout::Layout,
input::plugins::PluginConfig, input::plugins::PluginConfig,
ipc::ClientAttributes, ipc::ClientAttributes,
@ -69,6 +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>,
} }
impl<'a> PluginLoader<'a> { impl<'a> PluginLoader<'a> {
@ -89,6 +91,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: &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");
let mut connected_clients: Vec<ClientId> = let mut connected_clients: Vec<ClientId> =
@ -97,6 +100,7 @@ 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 mut plugin_loader = PluginLoader::new_from_existing_plugin_attributes( let mut plugin_loader = PluginLoader::new_from_existing_plugin_attributes(
&plugin_cache, &plugin_cache,
@ -115,6 +119,7 @@ impl<'a> PluginLoader<'a> {
default_layout, default_layout,
layout_dir, layout_dir,
default_mode, default_mode,
keybinds,
)?; )?;
plugin_loader plugin_loader
.load_module_from_memory() .load_module_from_memory()
@ -152,6 +157,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>,
) -> 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(
@ -173,6 +179,7 @@ impl<'a> PluginLoader<'a> {
default_layout, default_layout,
layout_dir, layout_dir,
default_mode, default_mode,
keybinds,
)?; )?;
if skip_cache { if skip_cache {
plugin_loader plugin_loader
@ -226,6 +233,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>,
) -> 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() {
@ -249,6 +257,7 @@ impl<'a> PluginLoader<'a> {
default_layout.clone(), default_layout.clone(),
layout_dir.clone(), layout_dir.clone(),
default_mode, default_mode,
keybinds.clone(),
)?; )?;
plugin_loader plugin_loader
.load_module_from_memory() .load_module_from_memory()
@ -278,6 +287,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: &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}");
@ -287,6 +297,7 @@ 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 mut plugin_loader = PluginLoader::new_from_existing_plugin_attributes( let mut plugin_loader = PluginLoader::new_from_existing_plugin_attributes(
&plugin_cache, &plugin_cache,
@ -305,6 +316,7 @@ impl<'a> PluginLoader<'a> {
default_layout, default_layout,
layout_dir, layout_dir,
default_mode, default_mode,
keybinds,
)?; )?;
plugin_loader plugin_loader
.compile_module() .compile_module()
@ -338,6 +350,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>,
) -> 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())
@ -366,6 +379,7 @@ impl<'a> PluginLoader<'a> {
default_layout, default_layout,
layout_dir, layout_dir,
default_mode, default_mode,
keybinds,
}) })
} }
pub fn new_from_existing_plugin_attributes( pub fn new_from_existing_plugin_attributes(
@ -385,6 +399,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>,
) -> 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) = {
@ -420,6 +435,7 @@ impl<'a> PluginLoader<'a> {
default_layout, default_layout,
layout_dir, layout_dir,
default_mode, default_mode,
keybinds,
) )
} }
pub fn new_from_different_client_id( pub fn new_from_different_client_id(
@ -439,6 +455,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>,
) -> 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 = {
@ -475,6 +492,7 @@ impl<'a> PluginLoader<'a> {
default_layout, default_layout,
layout_dir, layout_dir,
default_mode, default_mode,
keybinds,
) )
} }
pub fn load_module_from_memory(&mut self) -> Result<Module> { pub fn load_module_from_memory(&mut self) -> Result<Module> {
@ -731,6 +749,7 @@ impl<'a> PluginLoader<'a> {
self.default_layout.clone(), self.default_layout.clone(),
self.layout_dir.clone(), self.layout_dir.clone(),
self.default_mode, self.default_mode,
self.keybinds.clone(),
)?; )?;
plugin_loader_for_client plugin_loader_for_client
.load_module_from_memory() .load_module_from_memory()
@ -832,6 +851,11 @@ 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
.as_ref()
.unwrap_or_else(|| &self.client_attributes.keybinds)
.clone(),
stdin_pipe, stdin_pipe,
stdout_pipe, stdout_pipe,
}; };

View file

@ -22,6 +22,7 @@ use zellij_utils::{
data::InputMode, data::InputMode,
data::PluginCapabilities, data::PluginCapabilities,
input::command::TerminalAction, input::command::TerminalAction,
input::keybinds::Keybinds,
input::layout::{Layout, PluginUserConfiguration, RunPlugin, RunPluginLocation}, input::layout::{Layout, PluginUserConfiguration, RunPlugin, RunPluginLocation},
input::plugins::PluginConfig, input::plugins::PluginConfig,
ipc::ClientAttributes, ipc::ClientAttributes,
@ -289,6 +290,7 @@ pub struct PluginEnv {
pub subscriptions: Arc<Mutex<Subscriptions>>, pub subscriptions: Arc<Mutex<Subscriptions>>,
pub stdin_pipe: Arc<Mutex<VecDeque<u8>>>, pub stdin_pipe: Arc<Mutex<VecDeque<u8>>>,
pub stdout_pipe: Arc<Mutex<VecDeque<u8>>>, pub stdout_pipe: Arc<Mutex<VecDeque<u8>>>,
pub keybinds: Keybinds,
} }
#[derive(Clone)] #[derive(Clone)]
@ -424,4 +426,10 @@ impl RunningPlugin {
false false
} }
} }
pub fn update_keybinds(&mut self, keybinds: Keybinds) {
self.store.data_mut().keybinds = keybinds;
}
pub fn update_default_mode(&mut self, default_mode: InputMode) {
self.store.data_mut().default_mode = default_mode;
}
} }

View file

@ -6492,7 +6492,7 @@ pub fn disconnect_other_clients_plugins_command() {
#[test] #[test]
#[ignore] #[ignore]
pub fn rebind_keys_plugin_command() { pub fn reconfigure_plugin_command() {
let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its let temp_folder = tempdir().unwrap(); // placed explicitly in the test scope because its
// destructor removes the directory // destructor removes the directory
let plugin_host_folder = PathBuf::from(temp_folder.path()); let plugin_host_folder = PathBuf::from(temp_folder.path());
@ -6527,7 +6527,7 @@ pub fn rebind_keys_plugin_command() {
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!(
received_server_instruction, received_server_instruction,
ServerInstruction::RebindKeys, ServerInstruction::Reconfigure,
server_receiver, server_receiver,
1 1
); );
@ -6555,20 +6555,20 @@ pub fn rebind_keys_plugin_command() {
std::thread::sleep(std::time::Duration::from_millis(500)); std::thread::sleep(std::time::Duration::from_millis(500));
teardown(); teardown();
server_thread.join().unwrap(); // this might take a while if the cache is cold server_thread.join().unwrap(); // this might take a while if the cache is cold
let rebind_keys_event = received_server_instruction let reconfigure_event = received_server_instruction
.lock() .lock()
.unwrap() .unwrap()
.iter() .iter()
.rev() .rev()
.find_map(|i| { .find_map(|i| {
if let ServerInstruction::RebindKeys(..) = i { if let ServerInstruction::Reconfigure(..) = i {
Some(i.clone()) Some(i.clone())
} else { } else {
None None
} }
}) })
.clone(); .clone();
assert_snapshot!(format!("{:#?}", rebind_keys_event)); assert_snapshot!(format!("{:#?}", reconfigure_event));
} }
#[test] #[test]

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-server/src/plugins/./unit/plugin_tests.rs source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 5500 assertion_line: 5505
expression: "format!(\"{:#?}\", permissions)" expression: "format!(\"{:#?}\", permissions)"
--- ---
Some( Some(
@ -14,6 +14,6 @@ Some(
WebAccess, WebAccess,
ReadCliPipes, ReadCliPipes,
MessageAndLaunchOtherPlugins, MessageAndLaunchOtherPlugins,
RebindKeys, Reconfigure,
], ],
) )

View file

@ -0,0 +1,11 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 6571
expression: "format!(\"{:#?}\", reconfigure_event)"
---
Some(
Reconfigure(
1,
"\n keybinds {\n locked {\n bind \"a\" { NewTab; }\n }\n }\n ",
),
)

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-server/src/plugins/./unit/plugin_tests.rs source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 5409 assertion_line: 5414
expression: "format!(\"{:#?}\", new_tab_event)" expression: "format!(\"{:#?}\", new_tab_event)"
--- ---
Some( Some(
@ -16,6 +16,6 @@ Some(
WebAccess, WebAccess,
ReadCliPipes, ReadCliPipes,
MessageAndLaunchOtherPlugins, MessageAndLaunchOtherPlugins,
RebindKeys, Reconfigure,
], ],
) )

View file

@ -21,6 +21,7 @@ use zellij_utils::async_std::task::{self, JoinHandle};
use zellij_utils::consts::ZELLIJ_CACHE_DIR; use zellij_utils::consts::ZELLIJ_CACHE_DIR;
use zellij_utils::data::{InputMode, PermissionStatus, PermissionType, PipeMessage, PipeSource}; use zellij_utils::data::{InputMode, PermissionStatus, PermissionType, PipeMessage, PipeSource};
use zellij_utils::downloader::Downloader; use zellij_utils::downloader::Downloader;
use zellij_utils::input::keybinds::Keybinds;
use zellij_utils::input::permission::PermissionCache; use zellij_utils::input::permission::PermissionCache;
use zellij_utils::notify_debouncer_full::{notify::RecommendedWatcher, Debouncer, FileIdMap}; use zellij_utils::notify_debouncer_full::{notify::RecommendedWatcher, Debouncer, FileIdMap};
use zellij_utils::plugin_api::event::ProtobufEvent; use zellij_utils::plugin_api::event::ProtobufEvent;
@ -103,6 +104,7 @@ pub struct WasmBridge {
pending_pipes: PendingPipes, pending_pipes: PendingPipes,
layout_dir: Option<PathBuf>, layout_dir: Option<PathBuf>,
default_mode: InputMode, default_mode: InputMode,
keybinds: HashMap<ClientId, Keybinds>,
} }
impl WasmBridge { impl WasmBridge {
@ -149,6 +151,7 @@ impl WasmBridge {
pending_pipes: Default::default(), pending_pipes: Default::default(),
layout_dir, layout_dir,
default_mode, default_mode,
keybinds: HashMap::new(),
} }
} }
pub fn load_plugin( pub fn load_plugin(
@ -206,6 +209,7 @@ impl WasmBridge {
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.default_mode;
let keybinds = self.keybinds.get(&client_id).cloned();
async move { async move {
let _ = senders.send_to_background_jobs( let _ = senders.send_to_background_jobs(
BackgroundJob::AnimatePluginLoading(plugin_id), BackgroundJob::AnimatePluginLoading(plugin_id),
@ -254,6 +258,7 @@ impl WasmBridge {
skip_cache, skip_cache,
layout_dir, layout_dir,
default_mode, default_mode,
keybinds,
) { ) {
Ok(_) => handle_plugin_successful_loading(&senders, plugin_id), Ok(_) => handle_plugin_successful_loading(&senders, plugin_id),
Err(e) => handle_plugin_loading_failure( Err(e) => handle_plugin_loading_failure(
@ -346,6 +351,7 @@ impl WasmBridge {
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.default_mode;
let keybinds = self.keybinds.clone();
async move { async move {
match PluginLoader::reload_plugin( match PluginLoader::reload_plugin(
first_plugin_id, first_plugin_id,
@ -364,6 +370,7 @@ impl WasmBridge {
default_layout.clone(), default_layout.clone(),
layout_dir.clone(), layout_dir.clone(),
default_mode, default_mode,
&keybinds,
) { ) {
Ok(_) => { Ok(_) => {
handle_plugin_successful_loading(&senders, first_plugin_id); handle_plugin_successful_loading(&senders, first_plugin_id);
@ -390,6 +397,7 @@ impl WasmBridge {
default_layout.clone(), default_layout.clone(),
layout_dir.clone(), layout_dir.clone(),
default_mode, default_mode,
&keybinds,
) { ) {
Ok(_) => handle_plugin_successful_loading(&senders, *plugin_id), Ok(_) => handle_plugin_successful_loading(&senders, *plugin_id),
Err(e) => handle_plugin_loading_failure( Err(e) => handle_plugin_loading_failure(
@ -443,6 +451,7 @@ 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(),
) { ) {
Ok(_) => { Ok(_) => {
let _ = self let _ = self
@ -795,6 +804,51 @@ impl WasmBridge {
.unwrap() .unwrap()
.run_plugin_of_plugin_id(plugin_id) .run_plugin_of_plugin_id(plugin_id)
} }
pub fn reconfigure(
&mut self,
client_id: ClientId,
keybinds: Option<Keybinds>,
default_mode: Option<InputMode>,
) -> Result<()> {
let plugins_to_reconfigure: Vec<Arc<Mutex<RunningPlugin>>> = self
.plugin_map
.lock()
.unwrap()
.running_plugins()
.iter()
.cloned()
.filter_map(|(_plugin_id, c_id, running_plugin)| {
if c_id == client_id {
Some(running_plugin.clone())
} else {
None
}
})
.collect();
if let Some(default_mode) = default_mode.as_ref() {
self.default_mode = *default_mode;
}
if let Some(keybinds) = keybinds.as_ref() {
self.keybinds.insert(client_id, keybinds.clone());
}
for running_plugin in plugins_to_reconfigure {
task::spawn({
let running_plugin = running_plugin.clone();
let keybinds = keybinds.clone();
async move {
let mut running_plugin = running_plugin.lock().unwrap();
if let Some(keybinds) = keybinds {
running_plugin.update_keybinds(keybinds);
}
if let Some(default_mode) = default_mode {
running_plugin.update_default_mode(default_mode);
}
}
});
}
Ok(())
}
fn apply_cached_events_and_resizes_for_plugin( fn apply_cached_events_and_resizes_for_plugin(
&mut self, &mut self,
plugin_id: PluginId, plugin_id: PluginId,
@ -1288,6 +1342,18 @@ pub fn apply_event_to_plugin(
let err_context = || format!("Failed to apply event to plugin {plugin_id}"); let err_context = || format!("Failed to apply event to plugin {plugin_id}");
match check_event_permission(running_plugin.store.data(), event) { match check_event_permission(running_plugin.store.data(), event) {
(PermissionStatus::Granted, _) => { (PermissionStatus::Granted, _) => {
let mut event = event.clone();
if let Event::ModeUpdate(mode_info) = &mut event {
// we do this because there can be some cases where this event arrives here with
// the wrong keybindings or default mode (for example: when triggered from the CLI,
// where we do not know the target client_id and thus don't know if their keybindings are the
// default or if they have changed at runtime), the keybindings in running_plugin
// should always be up-to-date. Ideally, we would have changed the keybindings in
// ModeInfo to an Option, but alas - this is already part of our contract and that
// would be a breaking change.
mode_info.keybinds = running_plugin.store.data().keybinds.to_keybinds_vec();
mode_info.base_mode = Some(running_plugin.store.data().default_mode);
}
let protobuf_event: ProtobufEvent = event let protobuf_event: ProtobufEvent = event
.clone() .clone()
.try_into() .try_into()

View file

@ -61,6 +61,7 @@ macro_rules! apply_action {
$env.default_shell.clone(), $env.default_shell.clone(),
$env.default_layout.clone(), $env.default_layout.clone(),
None, None,
$env.keybinds.clone(),
$env.default_mode.clone(), $env.default_mode.clone(),
) { ) {
log::error!("{}: {:?}", $error_message(), e); log::error!("{}: {:?}", $error_message(), e);
@ -244,7 +245,7 @@ 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::RebindKeys(new_keybinds) => rebind_keys(env, new_keybinds)?, PluginCommand::Reconfigure(new_config) => reconfigure(env, new_config)?,
}, },
(PermissionStatus::Denied, permission) => { (PermissionStatus::Denied, permission) => {
log::error!( log::error!(
@ -781,11 +782,11 @@ fn close_self(env: &PluginEnv) {
.non_fatal(); .non_fatal();
} }
fn rebind_keys(env: &PluginEnv, new_keybinds: String) -> Result<()> { fn reconfigure(env: &PluginEnv, new_config: String) -> Result<()> {
let err_context = || "Failed to rebind keys"; 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::RebindKeys(client_id, new_keybinds)) .send_to_server(ServerInstruction::Reconfigure(client_id, new_config))
.with_context(err_context)?; .with_context(err_context)?;
Ok(()) Ok(())
} }
@ -1446,7 +1447,7 @@ fn check_command_permission(
| PluginCommand::CliPipeOutput(..) => PermissionType::ReadCliPipes, | PluginCommand::CliPipeOutput(..) => PermissionType::ReadCliPipes,
PluginCommand::MessageToPlugin(..) => PermissionType::MessageAndLaunchOtherPlugins, PluginCommand::MessageToPlugin(..) => PermissionType::MessageAndLaunchOtherPlugins,
PluginCommand::DumpSessionLayout => PermissionType::ReadApplicationState, PluginCommand::DumpSessionLayout => PermissionType::ReadApplicationState,
PluginCommand::RebindKeys(..) => PermissionType::RebindKeys, PluginCommand::Reconfigure(..) => PermissionType::Reconfigure,
_ => return (PermissionStatus::Granted, None), _ => return (PermissionStatus::Granted, None),
}; };

View file

@ -19,6 +19,7 @@ use zellij_utils::{
actions::{Action, SearchDirection, SearchOption}, actions::{Action, SearchDirection, SearchOption},
command::TerminalAction, command::TerminalAction,
get_mode_info, get_mode_info,
keybinds::Keybinds,
layout::Layout, layout::Layout,
}, },
ipc::{ ipc::{
@ -38,6 +39,7 @@ pub(crate) fn route_action(
default_shell: Option<TerminalAction>, default_shell: Option<TerminalAction>,
default_layout: Box<Layout>, default_layout: Box<Layout>,
mut seen_cli_pipes: Option<&mut HashSet<String>>, mut seen_cli_pipes: Option<&mut HashSet<String>>,
client_keybinds: Keybinds,
default_mode: InputMode, default_mode: InputMode,
) -> Result<bool> { ) -> Result<bool> {
let mut should_break = false; let mut should_break = false;
@ -99,7 +101,13 @@ pub(crate) fn route_action(
.send_to_plugin(PluginInstruction::Update(vec![( .send_to_plugin(PluginInstruction::Update(vec![(
None, None,
Some(client_id), Some(client_id),
Event::ModeUpdate(get_mode_info(mode, attrs, capabilities, Some(default_mode))), Event::ModeUpdate(get_mode_info(
mode,
attrs,
capabilities,
&client_keybinds,
Some(default_mode),
)),
)])) )]))
.with_context(err_context)?; .with_context(err_context)?;
senders senders
@ -107,7 +115,13 @@ pub(crate) fn route_action(
.with_context(err_context)?; .with_context(err_context)?;
senders senders
.send_to_screen(ScreenInstruction::ChangeMode( .send_to_screen(ScreenInstruction::ChangeMode(
get_mode_info(mode, attrs, capabilities, Some(default_mode)), get_mode_info(
mode,
attrs,
capabilities,
&client_keybinds,
Some(default_mode),
),
client_id, client_id,
)) ))
.with_context(err_context)?; .with_context(err_context)?;
@ -349,6 +363,7 @@ pub(crate) fn route_action(
input_mode, input_mode,
attrs, attrs,
capabilities, capabilities,
&client_keybinds,
Some(default_mode), Some(default_mode),
)), )),
)])) )]))
@ -363,6 +378,7 @@ pub(crate) fn route_action(
input_mode, input_mode,
attrs, attrs,
capabilities, capabilities,
&client_keybinds,
Some(default_mode), Some(default_mode),
))) )))
.with_context(err_context)?; .with_context(err_context)?;
@ -1025,7 +1041,20 @@ 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),
rlocked_sessions.default_mode, rlocked_sessions
.client_keybinds
.get(&client_id)
.unwrap_or(
&rlocked_sessions
.client_attributes
.keybinds,
)
.clone(),
rlocked_sessions
.default_mode
.get(&client_id)
.unwrap_or(&InputMode::Normal)
.clone(),
)? { )? {
should_break = true; should_break = true;
} }
@ -1050,7 +1079,16 @@ 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),
rlocked_sessions.default_mode, rlocked_sessions
.client_keybinds
.get(&client_id)
.unwrap_or(&rlocked_sessions.client_attributes.keybinds)
.clone(),
rlocked_sessions
.default_mode
.get(&client_id)
.unwrap_or(&InputMode::Normal)
.clone(),
)? { )? {
should_break = true; should_break = true;
} }

View file

@ -361,7 +361,11 @@ pub enum ScreenInstruction {
DumpLayoutToHd, DumpLayoutToHd,
RenameSession(String, ClientId), // String -> new name RenameSession(String, ClientId), // String -> new name
ListClientsMetadata(Option<PathBuf>, ClientId), // Option<PathBuf> - default shell ListClientsMetadata(Option<PathBuf>, ClientId), // Option<PathBuf> - default shell
RebindKeys(Keybinds, ClientId), Reconfigure {
client_id: ClientId,
keybinds: Option<Keybinds>,
default_mode: Option<InputMode>,
},
} }
impl From<&ScreenInstruction> for ScreenContext { impl From<&ScreenInstruction> for ScreenContext {
@ -546,7 +550,7 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::DumpLayoutToHd => ScreenContext::DumpLayoutToHd, ScreenInstruction::DumpLayoutToHd => ScreenContext::DumpLayoutToHd,
ScreenInstruction::RenameSession(..) => ScreenContext::RenameSession, ScreenInstruction::RenameSession(..) => ScreenContext::RenameSession,
ScreenInstruction::ListClientsMetadata(..) => ScreenContext::ListClientsMetadata, ScreenInstruction::ListClientsMetadata(..) => ScreenContext::ListClientsMetadata,
ScreenInstruction::RebindKeys(..) => ScreenContext::RebindKeys, ScreenInstruction::Reconfigure { .. } => ScreenContext::Reconfigure,
} }
} }
} }
@ -1214,7 +1218,7 @@ impl Screen {
let tab_name = tab_name.unwrap_or_else(|| String::new()); let tab_name = tab_name.unwrap_or_else(|| String::new());
let position = self.tabs.len(); let position = self.tabs.len();
let tab = Tab::new( let mut tab = Tab::new(
tab_index, tab_index,
position, position,
tab_name, tab_name,
@ -1245,6 +1249,9 @@ impl Screen {
self.styled_underlines, self.styled_underlines,
self.explicitly_disable_kitty_keyboard_protocol, self.explicitly_disable_kitty_keyboard_protocol,
); );
for (client_id, mode_info) in &self.mode_info {
tab.change_mode_info(mode_info.clone(), *client_id);
}
self.tabs.insert(tab_index, tab); self.tabs.insert(tab_index, tab);
Ok(()) Ok(())
} }
@ -2151,17 +2158,30 @@ impl Screen {
} }
Ok(()) Ok(())
} }
pub fn rebind_keys(&mut self, new_keybinds: Keybinds, client_id: ClientId) -> Result<()> { pub fn reconfigure_mode_info(
&mut self,
new_keybinds: Option<Keybinds>,
new_default_mode: Option<InputMode>,
client_id: ClientId,
) -> Result<()> {
if self.connected_clients_contains(&client_id) { if self.connected_clients_contains(&client_id) {
let should_update_mode_info = new_keybinds.is_some() || new_default_mode.is_some();
let mode_info = self let mode_info = self
.mode_info .mode_info
.entry(client_id) .entry(client_id)
.or_insert_with(|| self.default_mode_info.clone()); .or_insert_with(|| self.default_mode_info.clone());
mode_info.update_keybinds(new_keybinds); if let Some(new_keybinds) = new_keybinds {
for tab in self.tabs.values_mut() { mode_info.update_keybinds(new_keybinds);
tab.change_mode_info(mode_info.clone(), client_id); }
tab.mark_active_pane_for_rerender(client_id); if let Some(new_default_mode) = new_default_mode {
tab.update_input_modes()?; mode_info.update_default_mode(new_default_mode);
}
if should_update_mode_info {
for tab in self.tabs.values_mut() {
tab.change_mode_info(mode_info.clone(), client_id);
tab.mark_active_pane_for_rerender(client_id);
tab.update_input_modes()?;
}
} }
} else { } else {
log::error!("Could not find client_id {client_id} to rebind keys"); log::error!("Could not find client_id {client_id} to rebind keys");
@ -2363,6 +2383,7 @@ pub(crate) fn screen_thread_main(
// ¯\_(ツ)_/¯ // ¯\_(ツ)_/¯
arrow_fonts: !arrow_fonts, arrow_fonts: !arrow_fonts,
}, },
&client_attributes.keybinds,
config_options.default_mode, config_options.default_mode,
), ),
draw_pane_frames, draw_pane_frames,
@ -4028,8 +4049,14 @@ pub(crate) fn screen_thread_main(
} }
screen.unblock_input()?; screen.unblock_input()?;
}, },
ScreenInstruction::RebindKeys(new_keybinds, client_id) => { ScreenInstruction::Reconfigure {
screen.rebind_keys(new_keybinds, client_id).non_fatal(); client_id,
keybinds,
default_mode,
} => {
screen
.reconfigure_mode_info(keybinds, default_mode, client_id)
.non_fatal();
}, },
} }
} }

View file

@ -114,6 +114,7 @@ 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 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();
@ -130,7 +131,14 @@ fn send_cli_action_to_server(
default_shell.clone(), default_shell.clone(),
default_layout.clone(), default_layout.clone(),
None, None,
default_mode, client_keybinds
.get(&client_id)
.unwrap_or(&session_metadata.client_attributes.keybinds)
.clone(),
default_mode
.get(&client_id)
.unwrap_or(&InputMode::Normal)
.clone(),
) )
.unwrap(); .unwrap();
} }
@ -578,7 +586,7 @@ impl MockScreen {
layout, layout,
client_input_modes: HashMap::new(), client_input_modes: HashMap::new(),
client_keybinds: HashMap::new(), client_keybinds: HashMap::new(),
default_mode: InputMode::Normal, default_mode: HashMap::new(),
}; };
let os_input = FakeInputOutput::default(); let os_input = FakeInputOutput::default();

View file

@ -809,8 +809,8 @@ pub fn dump_session_layout() {
} }
/// Rebind keys for the current user /// Rebind keys for the current user
pub fn rebind_keys(keys: String) { pub fn reconfigure(new_config: String) {
let plugin_command = PluginCommand::RebindKeys(keys); let plugin_command = PluginCommand::Reconfigure(new_config);
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() };

View file

@ -120,6 +120,13 @@ keybinds {
}; };
SwitchToMode "Normal" SwitchToMode "Normal"
} }
bind "c" {
LaunchOrFocusPlugin "configuration" {
floating true
move_to_focused_tab true
};
SwitchToMode "Normal"
}
} }
tmux { tmux {
bind "[" { SwitchToMode "Scroll"; } bind "[" { SwitchToMode "Scroll"; }
@ -147,6 +154,7 @@ keybinds {
shared_except "locked" { shared_except "locked" {
bind "Ctrl g" { SwitchToMode "Locked"; } bind "Ctrl g" { SwitchToMode "Locked"; }
bind "Ctrl q" { Quit; } bind "Ctrl q" { Quit; }
bind "Alt f" { ToggleFloatingPanes; }
bind "Alt n" { NewPane; } bind "Alt n" { NewPane; }
bind "Alt i" { MoveTab "Left"; } bind "Alt i" { MoveTab "Left"; }
bind "Alt o" { MoveTab "Right"; } bind "Alt o" { MoveTab "Right"; }
@ -197,6 +205,7 @@ plugins {
filepicker location="zellij:strider" { filepicker location="zellij:strider" {
cwd "/" cwd "/"
} }
configuration location="zellij:configuration"
} }
// Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP // Choose what to do when zellij receives SIGTERM, SIGINT, SIGQUIT or SIGHUP

Binary file not shown.

View file

@ -119,7 +119,7 @@ pub mod plugin_command {
#[prost(message, tag = "62")] #[prost(message, tag = "62")]
NewTabsWithLayoutInfoPayload(super::NewTabsWithLayoutInfoPayload), NewTabsWithLayoutInfoPayload(super::NewTabsWithLayoutInfoPayload),
#[prost(string, tag = "63")] #[prost(string, tag = "63")]
RebindKeysPayload(::prost::alloc::string::String), ReconfigurePayload(::prost::alloc::string::String),
} }
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
@ -433,7 +433,7 @@ pub enum CommandName {
DumpSessionLayout = 84, DumpSessionLayout = 84,
CloseSelf = 85, CloseSelf = 85,
NewTabsWithLayoutInfo = 86, NewTabsWithLayoutInfo = 86,
RebindKeys = 87, Reconfigure = 87,
} }
impl CommandName { impl CommandName {
/// String value of the enum field names used in the ProtoBuf definition. /// String value of the enum field names used in the ProtoBuf definition.
@ -529,7 +529,7 @@ impl CommandName {
CommandName::DumpSessionLayout => "DumpSessionLayout", CommandName::DumpSessionLayout => "DumpSessionLayout",
CommandName::CloseSelf => "CloseSelf", CommandName::CloseSelf => "CloseSelf",
CommandName::NewTabsWithLayoutInfo => "NewTabsWithLayoutInfo", CommandName::NewTabsWithLayoutInfo => "NewTabsWithLayoutInfo",
CommandName::RebindKeys => "RebindKeys", CommandName::Reconfigure => "Reconfigure",
} }
} }
/// Creates an enum from field names used in the ProtoBuf definition. /// Creates an enum from field names used in the ProtoBuf definition.
@ -622,7 +622,7 @@ impl CommandName {
"DumpSessionLayout" => Some(Self::DumpSessionLayout), "DumpSessionLayout" => Some(Self::DumpSessionLayout),
"CloseSelf" => Some(Self::CloseSelf), "CloseSelf" => Some(Self::CloseSelf),
"NewTabsWithLayoutInfo" => Some(Self::NewTabsWithLayoutInfo), "NewTabsWithLayoutInfo" => Some(Self::NewTabsWithLayoutInfo),
"RebindKeys" => Some(Self::RebindKeys), "Reconfigure" => Some(Self::Reconfigure),
_ => None, _ => None,
} }
} }

View file

@ -10,7 +10,7 @@ pub enum PermissionType {
WebAccess = 6, WebAccess = 6,
ReadCliPipes = 7, ReadCliPipes = 7,
MessageAndLaunchOtherPlugins = 8, MessageAndLaunchOtherPlugins = 8,
RebindKeys = 9, Reconfigure = 9,
} }
impl PermissionType { impl PermissionType {
/// String value of the enum field names used in the ProtoBuf definition. /// String value of the enum field names used in the ProtoBuf definition.
@ -30,7 +30,7 @@ impl PermissionType {
PermissionType::MessageAndLaunchOtherPlugins => { PermissionType::MessageAndLaunchOtherPlugins => {
"MessageAndLaunchOtherPlugins" "MessageAndLaunchOtherPlugins"
} }
PermissionType::RebindKeys => "RebindKeys", PermissionType::Reconfigure => "Reconfigure",
} }
} }
/// Creates an enum from field names used in the ProtoBuf definition. /// Creates an enum from field names used in the ProtoBuf definition.
@ -45,7 +45,7 @@ impl PermissionType {
"WebAccess" => Some(Self::WebAccess), "WebAccess" => Some(Self::WebAccess),
"ReadCliPipes" => Some(Self::ReadCliPipes), "ReadCliPipes" => Some(Self::ReadCliPipes),
"MessageAndLaunchOtherPlugins" => Some(Self::MessageAndLaunchOtherPlugins), "MessageAndLaunchOtherPlugins" => Some(Self::MessageAndLaunchOtherPlugins),
"RebindKeys" => Some(Self::RebindKeys), "Reconfigure" => Some(Self::Reconfigure),
_ => None, _ => None,
} }
} }

View file

@ -110,6 +110,7 @@ mod not_wasm {
add_plugin!(assets, "tab-bar.wasm"); add_plugin!(assets, "tab-bar.wasm");
add_plugin!(assets, "strider.wasm"); add_plugin!(assets, "strider.wasm");
add_plugin!(assets, "session-manager.wasm"); add_plugin!(assets, "session-manager.wasm");
add_plugin!(assets, "configuration.wasm");
assets assets
}; };
} }

View file

@ -942,7 +942,7 @@ pub enum Permission {
WebAccess, WebAccess,
ReadCliPipes, ReadCliPipes,
MessageAndLaunchOtherPlugins, MessageAndLaunchOtherPlugins,
RebindKeys, Reconfigure,
} }
impl PermissionType { impl PermissionType {
@ -963,7 +963,7 @@ impl PermissionType {
PermissionType::MessageAndLaunchOtherPlugins => { PermissionType::MessageAndLaunchOtherPlugins => {
"Send messages to and launch other plugins".to_owned() "Send messages to and launch other plugins".to_owned()
}, },
PermissionType::RebindKeys => "Rebind keys".to_owned(), PermissionType::Reconfigure => "Change Zellij runtime configuration".to_owned(),
} }
} }
} }
@ -1164,6 +1164,9 @@ impl ModeInfo {
pub fn update_keybinds(&mut self, keybinds: Keybinds) { pub fn update_keybinds(&mut self, keybinds: Keybinds) {
self.keybinds = keybinds.to_keybinds_vec(); self.keybinds = keybinds.to_keybinds_vec();
} }
pub fn update_default_mode(&mut self, new_default_mode: InputMode) {
self.base_mode = Some(new_default_mode);
}
} }
#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)] #[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
@ -1767,5 +1770,5 @@ pub enum PluginCommand {
DumpSessionLayout, DumpSessionLayout,
CloseSelf, CloseSelf,
NewTabsWithLayoutInfo(LayoutInfo), NewTabsWithLayoutInfo(LayoutInfo),
RebindKeys(String), // String -> stringified keybindings Reconfigure(String), // String -> stringified configuration
} }

View file

@ -353,7 +353,7 @@ pub enum ScreenContext {
RenameSession, RenameSession,
DumpLayoutToPlugin, DumpLayoutToPlugin,
ListClientsMetadata, ListClientsMetadata,
RebindKeys, Reconfigure,
} }
/// Stack call representations corresponding to the different types of [`PtyInstruction`]s. /// Stack call representations corresponding to the different types of [`PtyInstruction`]s.
@ -409,6 +409,7 @@ pub enum PluginContext {
KeybindPipe, KeybindPipe,
DumpLayoutToPlugin, DumpLayoutToPlugin,
ListClientsMetadata, ListClientsMetadata,
Reconfigure,
} }
/// Stack call representations corresponding to the different types of [`ClientInstruction`]s. /// Stack call representations corresponding to the different types of [`ClientInstruction`]s.
@ -457,7 +458,7 @@ pub enum ServerContext {
DisconnectAllClientsExcept, DisconnectAllClientsExcept,
ChangeMode, ChangeMode,
ChangeModeForAllClients, ChangeModeForAllClients,
RebindKeys, Reconfigure,
} }
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]

View file

@ -712,16 +712,6 @@ impl Action {
pub fn launches_plugin(&self, plugin_url: &str) -> bool { pub fn launches_plugin(&self, plugin_url: &str) -> bool {
match self { match self {
Action::LaunchPlugin(run_plugin_or_alias, ..) => { Action::LaunchPlugin(run_plugin_or_alias, ..) => {
log::info!(
"1: {:?} == {:?}",
run_plugin_or_alias.location_string(),
plugin_url
);
eprintln!(
"1: {:?} == {:?}",
run_plugin_or_alias.location_string(),
plugin_url
);
&run_plugin_or_alias.location_string() == plugin_url &run_plugin_or_alias.location_string() == plugin_url
}, },
Action::LaunchOrFocusPlugin(run_plugin_or_alias, ..) => { Action::LaunchOrFocusPlugin(run_plugin_or_alias, ..) => {

View file

@ -33,9 +33,10 @@ mod not_wasm {
mode: InputMode, mode: InputMode,
attributes: &ClientAttributes, attributes: &ClientAttributes,
capabilities: PluginCapabilities, capabilities: PluginCapabilities,
keybinds: &Keybinds,
base_mode: Option<InputMode>, base_mode: Option<InputMode>,
) -> ModeInfo { ) -> ModeInfo {
let keybinds = attributes.keybinds.to_keybinds_vec(); let keybinds = keybinds.to_keybinds_vec();
let session_name = envs::get_session_name().ok(); let session_name = envs::get_session_name().ok();
ModeInfo { ModeInfo {

View file

@ -65,6 +65,7 @@ impl PluginConfig {
|| tag == "compact-bar" || tag == "compact-bar"
|| tag == "strider" || tag == "strider"
|| tag == "session-manager" || tag == "session-manager"
|| tag == "configuration"
{ {
Some(PluginConfig { Some(PluginConfig {
path: PathBuf::from(&tag), path: PathBuf::from(&tag),

View file

@ -1649,6 +1649,10 @@ impl Options {
support_kitty_keyboard_protocol, support_kitty_keyboard_protocol,
}) })
} }
pub fn from_string(stringified_keybindings: &String) -> Result<Self, ConfigError> {
let document: KdlDocument = stringified_keybindings.parse()?;
Options::from_kdl(&document)
}
} }
impl Layout { impl Layout {

View file

@ -98,7 +98,7 @@ enum CommandName {
DumpSessionLayout = 84; DumpSessionLayout = 84;
CloseSelf = 85; CloseSelf = 85;
NewTabsWithLayoutInfo = 86; NewTabsWithLayoutInfo = 86;
RebindKeys = 87; Reconfigure = 87;
} }
message PluginCommand { message PluginCommand {
@ -156,7 +156,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 rebind_keys_payload = 63; string reconfigure_payload = 63;
} }
} }

View file

@ -888,11 +888,11 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
}, },
_ => Err("Mismatched payload for NewTabsWithLayoutInfo"), _ => Err("Mismatched payload for NewTabsWithLayoutInfo"),
}, },
Some(CommandName::RebindKeys) => match protobuf_plugin_command.payload { Some(CommandName::Reconfigure) => match protobuf_plugin_command.payload {
Some(Payload::RebindKeysPayload(rebind_keys_payload)) => { Some(Payload::ReconfigurePayload(reconfigure_payload)) => {
Ok(PluginCommand::RebindKeys(rebind_keys_payload)) Ok(PluginCommand::Reconfigure(reconfigure_payload))
}, },
_ => Err("Mismatched payload for RebindKeys"), _ => Err("Mismatched payload for Reconfigure"),
}, },
None => Err("Unrecognized plugin command"), None => Err("Unrecognized plugin command"),
} }
@ -1426,9 +1426,9 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
)), )),
}) })
}, },
PluginCommand::RebindKeys(rebind_keys_payload) => Ok(ProtobufPluginCommand { PluginCommand::Reconfigure(reconfigure_payload) => Ok(ProtobufPluginCommand {
name: CommandName::RebindKeys as i32, name: CommandName::Reconfigure as i32,
payload: Some(Payload::RebindKeysPayload(rebind_keys_payload)), payload: Some(Payload::ReconfigurePayload(reconfigure_payload)),
}), }),
} }
} }

View file

@ -12,5 +12,5 @@ enum PermissionType {
WebAccess = 6; WebAccess = 6;
ReadCliPipes = 7; ReadCliPipes = 7;
MessageAndLaunchOtherPlugins = 8; MessageAndLaunchOtherPlugins = 8;
RebindKeys = 9; Reconfigure = 9;
} }

View file

@ -24,7 +24,7 @@ impl TryFrom<ProtobufPermissionType> for PermissionType {
ProtobufPermissionType::MessageAndLaunchOtherPlugins => { ProtobufPermissionType::MessageAndLaunchOtherPlugins => {
Ok(PermissionType::MessageAndLaunchOtherPlugins) Ok(PermissionType::MessageAndLaunchOtherPlugins)
}, },
ProtobufPermissionType::RebindKeys => Ok(PermissionType::RebindKeys), ProtobufPermissionType::Reconfigure => Ok(PermissionType::Reconfigure),
} }
} }
} }
@ -50,7 +50,7 @@ impl TryFrom<PermissionType> for ProtobufPermissionType {
PermissionType::MessageAndLaunchOtherPlugins => { PermissionType::MessageAndLaunchOtherPlugins => {
Ok(ProtobufPermissionType::MessageAndLaunchOtherPlugins) Ok(ProtobufPermissionType::MessageAndLaunchOtherPlugins)
}, },
PermissionType::RebindKeys => Ok(ProtobufPermissionType::RebindKeys), PermissionType::Reconfigure => Ok(ProtobufPermissionType::Reconfigure),
} }
} }
} }

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-utils/src/setup.rs source: zellij-utils/src/setup.rs
assertion_line: 725 assertion_line: 753
expression: "format!(\"{:#?}\", config)" expression: "format!(\"{:#?}\", config)"
--- ---
Config { Config {
@ -117,6 +117,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -552,6 +562,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -997,6 +1017,16 @@ Config {
Normal, Normal,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -1590,6 +1620,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -2066,6 +2106,16 @@ Config {
}: [ }: [
PageScrollDown, PageScrollDown,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -2441,6 +2491,16 @@ Config {
Scroll, Scroll,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -2824,6 +2884,16 @@ Config {
}: [ }: [
PageScrollDown, PageScrollDown,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -3224,6 +3294,16 @@ Config {
Normal, Normal,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -3545,6 +3625,16 @@ Config {
Normal, Normal,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -3854,6 +3944,34 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'c',
),
key_modifiers: {},
}: [
LaunchOrFocusPlugin(
Alias(
PluginAlias {
name: "configuration",
configuration: Some(
PluginUserConfiguration(
{},
),
),
initial_cwd: None,
run_plugin: None,
},
),
true,
true,
false,
false,
),
SwitchToMode(
Normal,
),
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'd', 'd',
@ -3862,6 +3980,16 @@ Config {
}: [ }: [
Detach, Detach,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -4238,6 +4366,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -4620,6 +4758,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -5064,6 +5212,16 @@ Config {
}: [ }: [
Detach, Detach,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -5409,6 +5567,18 @@ Config {
), ),
initial_cwd: None, initial_cwd: None,
}, },
"configuration": RunPlugin {
_allow_exec_host_cmd: false,
location: Zellij(
PluginTag(
"configuration",
),
),
configuration: PluginUserConfiguration(
{},
),
initial_cwd: None,
},
"filepicker": RunPlugin { "filepicker": RunPlugin {
_allow_exec_host_cmd: false, _allow_exec_host_cmd: false,
location: Zellij( location: Zellij(

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-utils/src/setup.rs source: zellij-utils/src/setup.rs
assertion_line: 783 assertion_line: 811
expression: "format!(\"{:#?}\", config)" expression: "format!(\"{:#?}\", config)"
--- ---
Config { Config {
@ -117,6 +117,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -552,6 +562,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -997,6 +1017,16 @@ Config {
Normal, Normal,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -1590,6 +1620,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -2066,6 +2106,16 @@ Config {
}: [ }: [
PageScrollDown, PageScrollDown,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -2441,6 +2491,16 @@ Config {
Scroll, Scroll,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -2824,6 +2884,16 @@ Config {
}: [ }: [
PageScrollDown, PageScrollDown,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -3224,6 +3294,16 @@ Config {
Normal, Normal,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -3545,6 +3625,16 @@ Config {
Normal, Normal,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -3854,6 +3944,34 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'c',
),
key_modifiers: {},
}: [
LaunchOrFocusPlugin(
Alias(
PluginAlias {
name: "configuration",
configuration: Some(
PluginUserConfiguration(
{},
),
),
initial_cwd: None,
run_plugin: None,
},
),
true,
true,
false,
false,
),
SwitchToMode(
Normal,
),
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'd', 'd',
@ -3862,6 +3980,16 @@ Config {
}: [ }: [
Detach, Detach,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -4238,6 +4366,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -4620,6 +4758,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -5064,6 +5212,16 @@ Config {
}: [ }: [
Detach, Detach,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -5409,6 +5567,18 @@ Config {
), ),
initial_cwd: None, initial_cwd: None,
}, },
"configuration": RunPlugin {
_allow_exec_host_cmd: false,
location: Zellij(
PluginTag(
"configuration",
),
),
configuration: PluginUserConfiguration(
{},
),
initial_cwd: None,
},
"filepicker": RunPlugin { "filepicker": RunPlugin {
_allow_exec_host_cmd: false, _allow_exec_host_cmd: false,
location: Zellij( location: Zellij(

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-utils/src/setup.rs source: zellij-utils/src/setup.rs
assertion_line: 825 assertion_line: 853
expression: "format!(\"{:#?}\", config)" expression: "format!(\"{:#?}\", config)"
--- ---
Config { Config {
@ -134,6 +134,18 @@ Config {
), ),
initial_cwd: None, initial_cwd: None,
}, },
"configuration": RunPlugin {
_allow_exec_host_cmd: false,
location: Zellij(
PluginTag(
"configuration",
),
),
configuration: PluginUserConfiguration(
{},
),
initial_cwd: None,
},
"filepicker": RunPlugin { "filepicker": RunPlugin {
_allow_exec_host_cmd: false, _allow_exec_host_cmd: false,
location: Zellij( location: Zellij(

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-utils/src/setup.rs source: zellij-utils/src/setup.rs
assertion_line: 811 assertion_line: 839
expression: "format!(\"{:#?}\", config)" expression: "format!(\"{:#?}\", config)"
--- ---
Config { Config {
@ -117,6 +117,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -552,6 +562,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -997,6 +1017,16 @@ Config {
Normal, Normal,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -1590,6 +1620,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -2066,6 +2106,16 @@ Config {
}: [ }: [
PageScrollDown, PageScrollDown,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -2441,6 +2491,16 @@ Config {
Scroll, Scroll,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -2824,6 +2884,16 @@ Config {
}: [ }: [
PageScrollDown, PageScrollDown,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -3224,6 +3294,16 @@ Config {
Normal, Normal,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -3545,6 +3625,16 @@ Config {
Normal, Normal,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -3854,6 +3944,34 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'c',
),
key_modifiers: {},
}: [
LaunchOrFocusPlugin(
Alias(
PluginAlias {
name: "configuration",
configuration: Some(
PluginUserConfiguration(
{},
),
),
initial_cwd: None,
run_plugin: None,
},
),
true,
true,
false,
false,
),
SwitchToMode(
Normal,
),
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'd', 'd',
@ -3862,6 +3980,16 @@ Config {
}: [ }: [
Detach, Detach,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -4238,6 +4366,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -4620,6 +4758,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -5064,6 +5212,16 @@ Config {
}: [ }: [
Detach, Detach,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -5713,6 +5871,18 @@ Config {
), ),
initial_cwd: None, initial_cwd: None,
}, },
"configuration": RunPlugin {
_allow_exec_host_cmd: false,
location: Zellij(
PluginTag(
"configuration",
),
),
configuration: PluginUserConfiguration(
{},
),
initial_cwd: None,
},
"filepicker": RunPlugin { "filepicker": RunPlugin {
_allow_exec_host_cmd: false, _allow_exec_host_cmd: false,
location: Zellij( location: Zellij(

View file

@ -1,6 +1,6 @@
--- ---
source: zellij-utils/src/setup.rs source: zellij-utils/src/setup.rs
assertion_line: 797 assertion_line: 825
expression: "format!(\"{:#?}\", config)" expression: "format!(\"{:#?}\", config)"
--- ---
Config { Config {
@ -117,6 +117,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -552,6 +562,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -997,6 +1017,16 @@ Config {
Normal, Normal,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -1590,6 +1620,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -2066,6 +2106,16 @@ Config {
}: [ }: [
PageScrollDown, PageScrollDown,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -2441,6 +2491,16 @@ Config {
Scroll, Scroll,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -2824,6 +2884,16 @@ Config {
}: [ }: [
PageScrollDown, PageScrollDown,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -3224,6 +3294,16 @@ Config {
Normal, Normal,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -3545,6 +3625,16 @@ Config {
Normal, Normal,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -3854,6 +3944,34 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'c',
),
key_modifiers: {},
}: [
LaunchOrFocusPlugin(
Alias(
PluginAlias {
name: "configuration",
configuration: Some(
PluginUserConfiguration(
{},
),
),
initial_cwd: None,
run_plugin: None,
},
),
true,
true,
false,
false,
),
SwitchToMode(
Normal,
),
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'd', 'd',
@ -3862,6 +3980,16 @@ Config {
}: [ }: [
Detach, Detach,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -4238,6 +4366,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -4620,6 +4758,16 @@ Config {
Tmux, Tmux,
), ),
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -5064,6 +5212,16 @@ Config {
}: [ }: [
Detach, Detach,
], ],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier { KeyWithModifier {
bare_key: Char( bare_key: Char(
'g', 'g',
@ -5409,6 +5567,18 @@ Config {
), ),
initial_cwd: None, initial_cwd: None,
}, },
"configuration": RunPlugin {
_allow_exec_host_cmd: false,
location: Zellij(
PluginTag(
"configuration",
),
),
configuration: PluginUserConfiguration(
{},
),
initial_cwd: None,
},
"filepicker": RunPlugin { "filepicker": RunPlugin {
_allow_exec_host_cmd: false, _allow_exec_host_cmd: false,
location: Zellij( location: Zellij(