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",
]
[[package]]
name = "configuration"
version = "0.1.0"
dependencies = [
"ansi_term",
"chrono",
"zellij-tile",
]
[[package]]
name = "console"
version = "0.15.0"

View file

@ -37,6 +37,7 @@ members = [
"default-plugins/tab-bar",
"default-plugins/fixture-plugin-for-tests",
"default-plugins/session-manager",
"default-plugins/configuration",
"zellij-client",
"zellij-server",
"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::ReadCliPipes,
PermissionType::MessageAndLaunchOtherPlugins,
PermissionType::RebindKeys,
PermissionType::Reconfigure,
]);
self.configuration = configuration;
subscribe(&[
@ -320,7 +320,7 @@ impl ZellijPlugin for State {
);
},
BareKey::Char('0') if key.has_modifiers(&[KeyModifier::Ctrl]) => {
rebind_keys(
reconfigure(
"
keybinds {
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![
(s("Detach"), s("Detach"), action_key(&km, &[Action::Detach])),
(s("Session Manager"), s("Manager"), session_manager_key(&km)),
(s("Configure"), s("Config"), configuration_key(&km)),
(s("Select pane"), s("Select"), to_basemode_key),
]} else if mi.mode == IM::Tmux { vec![
(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 {
if keyvec.is_empty() {
return LinePart::default();

View file

@ -1,6 +1,6 @@
---
source: src/tests/e2e/cases.rs
assertion_line: 1050
assertion_line: 1064
expression: last_snapshot
---
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
assertion_line: 2349
assertion_line: 2372
expression: last_snapshot
---
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 ────┘
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/fixture-plugin-for-tests", 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-tile-utils", build: false},
WorkspaceMember{crate_name: "zellij-tile", build: false},

View file

@ -97,7 +97,7 @@ pub enum ServerInstruction {
DisconnectAllClientsExcept(ClientId),
ChangeMode(ClientId, InputMode),
ChangeModeForAllClients(InputMode),
RebindKeys(ClientId, String), // String -> stringified keybindings
Reconfigure(ClientId, String), // String -> stringified configuration
}
impl From<&ServerInstruction> for ServerContext {
@ -129,7 +129,7 @@ impl From<&ServerInstruction> for ServerContext {
ServerInstruction::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 client_keybinds: HashMap<ClientId, Keybinds>,
pub client_input_modes: HashMap<ClientId, InputMode>,
pub default_mode: InputMode,
pub default_mode: HashMap<ClientId, InputMode>,
screen_thread: Option<thread::JoinHandle<()>>,
pty_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,
&attrs,
session_data.capabilities,
session_data
.client_keybinds
.get(&client_id)
.unwrap_or(&session_data.client_attributes.keybinds),
Some(default_mode),
);
session_data
@ -911,24 +915,57 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
.unwrap()
.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
.write()
.unwrap()
.as_mut()
.unwrap()
.rebind_keys(client_id, new_keybinds)
.rebind_keys(client_id, new_config)
.clone();
if let Some(new_keybinds) = new_keybinds {
session_data
.write()
.unwrap()
.as_ref()
.unwrap()
.senders
.send_to_screen(ScreenInstruction::RebindKeys(new_keybinds, client_id))
.unwrap();
}
session_data
.write()
.unwrap()
.as_ref()
.unwrap()
.senders
.send_to_screen(ScreenInstruction::Reconfigure {
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();
},
}
}
@ -1167,7 +1204,7 @@ fn init_session(
plugin_thread: Some(plugin_thread),
pty_writer_thread: Some(pty_writer_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},
input::{
command::TerminalAction,
keybinds::Keybinds,
layout::{FloatingPaneLayout, Layout, Run, RunPlugin, RunPluginOrAlias, TiledPaneLayout},
plugins::PluginAliases,
},
@ -142,6 +143,11 @@ pub enum PluginInstruction {
message: MessageToPlugin,
},
UnblockCliPipes(Vec<PluginRenderAsset>),
Reconfigure {
client_id: ClientId,
keybinds: Option<Keybinds>,
default_mode: Option<InputMode>,
},
WatchFilesystem,
Exit,
}
@ -182,6 +188,7 @@ impl From<&PluginInstruction> for PluginContext {
PluginInstruction::WatchFilesystem => PluginContext::WatchFilesystem,
PluginInstruction::KeybindPipe { .. } => PluginContext::KeybindPipe,
PluginInstruction::DumpLayoutToPlugin(..) => PluginContext::DumpLayoutToPlugin,
PluginInstruction::Reconfigure { .. } => PluginContext::Reconfigure,
}
}
}
@ -734,6 +741,15 @@ pub(crate) fn plugin_thread_main(
.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 => {
wasm_bridge.start_fs_watcher_if_not_started();
},

View file

@ -29,6 +29,7 @@ use zellij_utils::{
data::{InputMode, PluginCapabilities},
errors::prelude::*,
input::command::TerminalAction,
input::keybinds::Keybinds,
input::layout::Layout,
input::plugins::PluginConfig,
ipc::ClientAttributes,
@ -69,6 +70,7 @@ pub struct PluginLoader<'a> {
default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
default_mode: InputMode,
keybinds: Option<Keybinds>,
}
impl<'a> PluginLoader<'a> {
@ -89,6 +91,7 @@ impl<'a> PluginLoader<'a> {
default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
default_mode: InputMode,
keybinds: &HashMap<ClientId, Keybinds>,
) -> Result<()> {
let err_context = || format!("failed to reload plugin {plugin_id} from memory");
let mut connected_clients: Vec<ClientId> =
@ -97,6 +100,7 @@ impl<'a> PluginLoader<'a> {
return Err(anyhow!("No connected clients, cannot reload plugin"));
}
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(
&plugin_cache,
@ -115,6 +119,7 @@ impl<'a> PluginLoader<'a> {
default_layout,
layout_dir,
default_mode,
keybinds,
)?;
plugin_loader
.load_module_from_memory()
@ -152,6 +157,7 @@ impl<'a> PluginLoader<'a> {
skip_cache: bool,
layout_dir: Option<PathBuf>,
default_mode: InputMode,
keybinds: Option<Keybinds>,
) -> Result<()> {
let err_context = || format!("failed to start plugin {plugin_id} for client {client_id}");
let mut plugin_loader = PluginLoader::new(
@ -173,6 +179,7 @@ impl<'a> PluginLoader<'a> {
default_layout,
layout_dir,
default_mode,
keybinds,
)?;
if skip_cache {
plugin_loader
@ -226,6 +233,7 @@ impl<'a> PluginLoader<'a> {
default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
default_mode: InputMode,
keybinds: Option<Keybinds>,
) -> Result<()> {
let mut new_plugins = HashSet::new();
for plugin_id in plugin_map.lock().unwrap().plugin_ids() {
@ -249,6 +257,7 @@ impl<'a> PluginLoader<'a> {
default_layout.clone(),
layout_dir.clone(),
default_mode,
keybinds.clone(),
)?;
plugin_loader
.load_module_from_memory()
@ -278,6 +287,7 @@ impl<'a> PluginLoader<'a> {
default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
default_mode: InputMode,
keybinds: &HashMap<ClientId, Keybinds>,
) -> Result<()> {
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"));
}
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(
&plugin_cache,
@ -305,6 +316,7 @@ impl<'a> PluginLoader<'a> {
default_layout,
layout_dir,
default_mode,
keybinds,
)?;
plugin_loader
.compile_module()
@ -338,6 +350,7 @@ impl<'a> PluginLoader<'a> {
default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
default_mode: InputMode,
keybinds: Option<Keybinds>,
) -> Result<Self> {
let plugin_own_data_dir = ZELLIJ_SESSION_CACHE_DIR
.join(Url::from(&plugin.location).to_string())
@ -366,6 +379,7 @@ impl<'a> PluginLoader<'a> {
default_layout,
layout_dir,
default_mode,
keybinds,
})
}
pub fn new_from_existing_plugin_attributes(
@ -385,6 +399,7 @@ impl<'a> PluginLoader<'a> {
default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
default_mode: InputMode,
keybinds: Option<Keybinds>,
) -> Result<Self> {
let err_context = || "Failed to find existing plugin";
let (running_plugin, _subscriptions, _workers) = {
@ -420,6 +435,7 @@ impl<'a> PluginLoader<'a> {
default_layout,
layout_dir,
default_mode,
keybinds,
)
}
pub fn new_from_different_client_id(
@ -439,6 +455,7 @@ impl<'a> PluginLoader<'a> {
default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
default_mode: InputMode,
keybinds: Option<Keybinds>,
) -> Result<Self> {
let err_context = || "Failed to find existing plugin";
let running_plugin = {
@ -475,6 +492,7 @@ impl<'a> PluginLoader<'a> {
default_layout,
layout_dir,
default_mode,
keybinds,
)
}
pub fn load_module_from_memory(&mut self) -> Result<Module> {
@ -731,6 +749,7 @@ impl<'a> PluginLoader<'a> {
self.default_layout.clone(),
self.layout_dir.clone(),
self.default_mode,
self.keybinds.clone(),
)?;
plugin_loader_for_client
.load_module_from_memory()
@ -832,6 +851,11 @@ impl<'a> PluginLoader<'a> {
layout_dir: self.layout_dir.clone(),
default_mode: self.default_mode.clone(),
subscriptions: Arc::new(Mutex::new(HashSet::new())),
keybinds: self
.keybinds
.as_ref()
.unwrap_or_else(|| &self.client_attributes.keybinds)
.clone(),
stdin_pipe,
stdout_pipe,
};

View file

@ -22,6 +22,7 @@ use zellij_utils::{
data::InputMode,
data::PluginCapabilities,
input::command::TerminalAction,
input::keybinds::Keybinds,
input::layout::{Layout, PluginUserConfiguration, RunPlugin, RunPluginLocation},
input::plugins::PluginConfig,
ipc::ClientAttributes,
@ -289,6 +290,7 @@ pub struct PluginEnv {
pub subscriptions: Arc<Mutex<Subscriptions>>,
pub stdin_pipe: Arc<Mutex<VecDeque<u8>>>,
pub stdout_pipe: Arc<Mutex<VecDeque<u8>>>,
pub keybinds: Keybinds,
}
#[derive(Clone)]
@ -424,4 +426,10 @@ impl RunningPlugin {
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]
#[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
// destructor removes the directory
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 server_thread = log_actions_in_thread!(
received_server_instruction,
ServerInstruction::RebindKeys,
ServerInstruction::Reconfigure,
server_receiver,
1
);
@ -6555,20 +6555,20 @@ pub fn rebind_keys_plugin_command() {
std::thread::sleep(std::time::Duration::from_millis(500));
teardown();
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()
.unwrap()
.iter()
.rev()
.find_map(|i| {
if let ServerInstruction::RebindKeys(..) = i {
if let ServerInstruction::Reconfigure(..) = i {
Some(i.clone())
} else {
None
}
})
.clone();
assert_snapshot!(format!("{:#?}", rebind_keys_event));
assert_snapshot!(format!("{:#?}", reconfigure_event));
}
#[test]

View file

@ -1,6 +1,6 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 5500
assertion_line: 5505
expression: "format!(\"{:#?}\", permissions)"
---
Some(
@ -14,6 +14,6 @@ Some(
WebAccess,
ReadCliPipes,
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
assertion_line: 5409
assertion_line: 5414
expression: "format!(\"{:#?}\", new_tab_event)"
---
Some(
@ -16,6 +16,6 @@ Some(
WebAccess,
ReadCliPipes,
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::data::{InputMode, PermissionStatus, PermissionType, PipeMessage, PipeSource};
use zellij_utils::downloader::Downloader;
use zellij_utils::input::keybinds::Keybinds;
use zellij_utils::input::permission::PermissionCache;
use zellij_utils::notify_debouncer_full::{notify::RecommendedWatcher, Debouncer, FileIdMap};
use zellij_utils::plugin_api::event::ProtobufEvent;
@ -103,6 +104,7 @@ pub struct WasmBridge {
pending_pipes: PendingPipes,
layout_dir: Option<PathBuf>,
default_mode: InputMode,
keybinds: HashMap<ClientId, Keybinds>,
}
impl WasmBridge {
@ -149,6 +151,7 @@ impl WasmBridge {
pending_pipes: Default::default(),
layout_dir,
default_mode,
keybinds: HashMap::new(),
}
}
pub fn load_plugin(
@ -206,6 +209,7 @@ impl WasmBridge {
let default_layout = self.default_layout.clone();
let layout_dir = self.layout_dir.clone();
let default_mode = self.default_mode;
let keybinds = self.keybinds.get(&client_id).cloned();
async move {
let _ = senders.send_to_background_jobs(
BackgroundJob::AnimatePluginLoading(plugin_id),
@ -254,6 +258,7 @@ impl WasmBridge {
skip_cache,
layout_dir,
default_mode,
keybinds,
) {
Ok(_) => handle_plugin_successful_loading(&senders, plugin_id),
Err(e) => handle_plugin_loading_failure(
@ -346,6 +351,7 @@ impl WasmBridge {
let default_layout = self.default_layout.clone();
let layout_dir = self.layout_dir.clone();
let default_mode = self.default_mode;
let keybinds = self.keybinds.clone();
async move {
match PluginLoader::reload_plugin(
first_plugin_id,
@ -364,6 +370,7 @@ impl WasmBridge {
default_layout.clone(),
layout_dir.clone(),
default_mode,
&keybinds,
) {
Ok(_) => {
handle_plugin_successful_loading(&senders, first_plugin_id);
@ -390,6 +397,7 @@ impl WasmBridge {
default_layout.clone(),
layout_dir.clone(),
default_mode,
&keybinds,
) {
Ok(_) => handle_plugin_successful_loading(&senders, *plugin_id),
Err(e) => handle_plugin_loading_failure(
@ -443,6 +451,7 @@ impl WasmBridge {
self.default_layout.clone(),
self.layout_dir.clone(),
self.default_mode,
self.keybinds.get(&client_id).cloned(),
) {
Ok(_) => {
let _ = self
@ -795,6 +804,51 @@ impl WasmBridge {
.unwrap()
.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(
&mut self,
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}");
match check_event_permission(running_plugin.store.data(), event) {
(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
.clone()
.try_into()

View file

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

View file

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

View file

@ -361,7 +361,11 @@ pub enum ScreenInstruction {
DumpLayoutToHd,
RenameSession(String, ClientId), // String -> new name
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 {
@ -546,7 +550,7 @@ impl From<&ScreenInstruction> for ScreenContext {
ScreenInstruction::DumpLayoutToHd => ScreenContext::DumpLayoutToHd,
ScreenInstruction::RenameSession(..) => ScreenContext::RenameSession,
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 position = self.tabs.len();
let tab = Tab::new(
let mut tab = Tab::new(
tab_index,
position,
tab_name,
@ -1245,6 +1249,9 @@ impl Screen {
self.styled_underlines,
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);
Ok(())
}
@ -2151,17 +2158,30 @@ impl Screen {
}
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) {
let should_update_mode_info = new_keybinds.is_some() || new_default_mode.is_some();
let mode_info = self
.mode_info
.entry(client_id)
.or_insert_with(|| self.default_mode_info.clone());
mode_info.update_keybinds(new_keybinds);
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()?;
if let Some(new_keybinds) = new_keybinds {
mode_info.update_keybinds(new_keybinds);
}
if let Some(new_default_mode) = new_default_mode {
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 {
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,
},
&client_attributes.keybinds,
config_options.default_mode,
),
draw_pane_frames,
@ -4028,8 +4049,14 @@ pub(crate) fn screen_thread_main(
}
screen.unblock_input()?;
},
ScreenInstruction::RebindKeys(new_keybinds, client_id) => {
screen.rebind_keys(new_keybinds, client_id).non_fatal();
ScreenInstruction::Reconfigure {
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 actions = Action::actions_from_cli(cli_action, Box::new(get_current_dir), None).unwrap();
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 client_attributes = ClientAttributes::default();
@ -130,7 +131,14 @@ fn send_cli_action_to_server(
default_shell.clone(),
default_layout.clone(),
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();
}
@ -578,7 +586,7 @@ impl MockScreen {
layout,
client_input_modes: HashMap::new(),
client_keybinds: HashMap::new(),
default_mode: InputMode::Normal,
default_mode: HashMap::new(),
};
let os_input = FakeInputOutput::default();

View file

@ -809,8 +809,8 @@ pub fn dump_session_layout() {
}
/// Rebind keys for the current user
pub fn rebind_keys(keys: String) {
let plugin_command = PluginCommand::RebindKeys(keys);
pub fn reconfigure(new_config: String) {
let plugin_command = PluginCommand::Reconfigure(new_config);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };

View file

@ -120,6 +120,13 @@ keybinds {
};
SwitchToMode "Normal"
}
bind "c" {
LaunchOrFocusPlugin "configuration" {
floating true
move_to_focused_tab true
};
SwitchToMode "Normal"
}
}
tmux {
bind "[" { SwitchToMode "Scroll"; }
@ -147,6 +154,7 @@ keybinds {
shared_except "locked" {
bind "Ctrl g" { SwitchToMode "Locked"; }
bind "Ctrl q" { Quit; }
bind "Alt f" { ToggleFloatingPanes; }
bind "Alt n" { NewPane; }
bind "Alt i" { MoveTab "Left"; }
bind "Alt o" { MoveTab "Right"; }
@ -197,6 +205,7 @@ plugins {
filepicker location="zellij:strider" {
cwd "/"
}
configuration location="zellij:configuration"
}
// 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")]
NewTabsWithLayoutInfoPayload(super::NewTabsWithLayoutInfoPayload),
#[prost(string, tag = "63")]
RebindKeysPayload(::prost::alloc::string::String),
ReconfigurePayload(::prost::alloc::string::String),
}
}
#[allow(clippy::derive_partial_eq_without_eq)]
@ -433,7 +433,7 @@ pub enum CommandName {
DumpSessionLayout = 84,
CloseSelf = 85,
NewTabsWithLayoutInfo = 86,
RebindKeys = 87,
Reconfigure = 87,
}
impl CommandName {
/// String value of the enum field names used in the ProtoBuf definition.
@ -529,7 +529,7 @@ impl CommandName {
CommandName::DumpSessionLayout => "DumpSessionLayout",
CommandName::CloseSelf => "CloseSelf",
CommandName::NewTabsWithLayoutInfo => "NewTabsWithLayoutInfo",
CommandName::RebindKeys => "RebindKeys",
CommandName::Reconfigure => "Reconfigure",
}
}
/// Creates an enum from field names used in the ProtoBuf definition.
@ -622,7 +622,7 @@ impl CommandName {
"DumpSessionLayout" => Some(Self::DumpSessionLayout),
"CloseSelf" => Some(Self::CloseSelf),
"NewTabsWithLayoutInfo" => Some(Self::NewTabsWithLayoutInfo),
"RebindKeys" => Some(Self::RebindKeys),
"Reconfigure" => Some(Self::Reconfigure),
_ => None,
}
}

View file

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

View file

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

View file

@ -942,7 +942,7 @@ pub enum Permission {
WebAccess,
ReadCliPipes,
MessageAndLaunchOtherPlugins,
RebindKeys,
Reconfigure,
}
impl PermissionType {
@ -963,7 +963,7 @@ impl PermissionType {
PermissionType::MessageAndLaunchOtherPlugins => {
"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) {
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)]
@ -1767,5 +1770,5 @@ pub enum PluginCommand {
DumpSessionLayout,
CloseSelf,
NewTabsWithLayoutInfo(LayoutInfo),
RebindKeys(String), // String -> stringified keybindings
Reconfigure(String), // String -> stringified configuration
}

View file

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

View file

@ -712,16 +712,6 @@ impl Action {
pub fn launches_plugin(&self, plugin_url: &str) -> bool {
match self {
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
},
Action::LaunchOrFocusPlugin(run_plugin_or_alias, ..) => {

View file

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

View file

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

View file

@ -1649,6 +1649,10 @@ impl Options {
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 {

View file

@ -98,7 +98,7 @@ enum CommandName {
DumpSessionLayout = 84;
CloseSelf = 85;
NewTabsWithLayoutInfo = 86;
RebindKeys = 87;
Reconfigure = 87;
}
message PluginCommand {
@ -156,7 +156,7 @@ message PluginCommand {
KillSessionsPayload kill_sessions_payload = 60;
string scan_host_folder_payload = 61;
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"),
},
Some(CommandName::RebindKeys) => match protobuf_plugin_command.payload {
Some(Payload::RebindKeysPayload(rebind_keys_payload)) => {
Ok(PluginCommand::RebindKeys(rebind_keys_payload))
Some(CommandName::Reconfigure) => match protobuf_plugin_command.payload {
Some(Payload::ReconfigurePayload(reconfigure_payload)) => {
Ok(PluginCommand::Reconfigure(reconfigure_payload))
},
_ => Err("Mismatched payload for RebindKeys"),
_ => Err("Mismatched payload for Reconfigure"),
},
None => Err("Unrecognized plugin command"),
}
@ -1426,9 +1426,9 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
)),
})
},
PluginCommand::RebindKeys(rebind_keys_payload) => Ok(ProtobufPluginCommand {
name: CommandName::RebindKeys as i32,
payload: Some(Payload::RebindKeysPayload(rebind_keys_payload)),
PluginCommand::Reconfigure(reconfigure_payload) => Ok(ProtobufPluginCommand {
name: CommandName::Reconfigure as i32,
payload: Some(Payload::ReconfigurePayload(reconfigure_payload)),
}),
}
}

View file

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

View file

@ -24,7 +24,7 @@ impl TryFrom<ProtobufPermissionType> for PermissionType {
ProtobufPermissionType::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 => {
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
assertion_line: 725
assertion_line: 753
expression: "format!(\"{:#?}\", config)"
---
Config {
@ -117,6 +117,16 @@ Config {
Tmux,
),
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -552,6 +562,16 @@ Config {
Tmux,
),
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -997,6 +1017,16 @@ Config {
Normal,
),
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -1590,6 +1620,16 @@ Config {
Tmux,
),
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -2066,6 +2106,16 @@ Config {
}: [
PageScrollDown,
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -2441,6 +2491,16 @@ Config {
Scroll,
),
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -2824,6 +2884,16 @@ Config {
}: [
PageScrollDown,
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -3224,6 +3294,16 @@ Config {
Normal,
),
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -3545,6 +3625,16 @@ Config {
Normal,
),
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -3854,6 +3944,34 @@ Config {
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 {
bare_key: Char(
'd',
@ -3862,6 +3980,16 @@ Config {
}: [
Detach,
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -4238,6 +4366,16 @@ Config {
Tmux,
),
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -4620,6 +4758,16 @@ Config {
Tmux,
),
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -5064,6 +5212,16 @@ Config {
}: [
Detach,
],
KeyWithModifier {
bare_key: Char(
'f',
),
key_modifiers: {
Alt,
},
}: [
ToggleFloatingPanes,
],
KeyWithModifier {
bare_key: Char(
'g',
@ -5409,6 +5567,18 @@ Config {
),
initial_cwd: None,
},
"configuration": RunPlugin {
_allow_exec_host_cmd: false,
location: Zellij(
PluginTag(
"configuration",
),
),
configuration: PluginUserConfiguration(
{},
),
initial_cwd: None,
},
"filepicker": RunPlugin {
_allow_exec_host_cmd: false,
location: Zellij(

View file

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

View file

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

View file

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

View file

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