feat(plugins): rebind keys api (#3680)
* feat(plugins): add API to explicitly unbind/rebind specific keys in specific modes * style(fmt): rustfmt
This commit is contained in:
parent
5ae36ed58f
commit
0c9d72c51e
11 changed files with 697 additions and 27 deletions
|
|
@ -445,6 +445,86 @@ impl ZellijPlugin for State {
|
|||
skip_plugin_cache,
|
||||
)
|
||||
},
|
||||
BareKey::Char('y') if key.has_modifiers(&[KeyModifier::Alt]) => {
|
||||
let write_to_disk = true;
|
||||
let mut keys_to_unbind = vec![
|
||||
(
|
||||
InputMode::Locked,
|
||||
KeyWithModifier::new(BareKey::Char('g')).with_ctrl_modifier(),
|
||||
),
|
||||
(
|
||||
InputMode::Normal,
|
||||
KeyWithModifier::new(BareKey::Char('g')).with_ctrl_modifier(),
|
||||
),
|
||||
(
|
||||
InputMode::Pane,
|
||||
KeyWithModifier::new(BareKey::Char('g')).with_ctrl_modifier(),
|
||||
),
|
||||
(
|
||||
InputMode::Tab,
|
||||
KeyWithModifier::new(BareKey::Char('g')).with_ctrl_modifier(),
|
||||
),
|
||||
(
|
||||
InputMode::Resize,
|
||||
KeyWithModifier::new(BareKey::Char('g')).with_ctrl_modifier(),
|
||||
),
|
||||
(
|
||||
InputMode::Move,
|
||||
KeyWithModifier::new(BareKey::Char('g')).with_ctrl_modifier(),
|
||||
),
|
||||
(
|
||||
InputMode::Search,
|
||||
KeyWithModifier::new(BareKey::Char('g')).with_ctrl_modifier(),
|
||||
),
|
||||
(
|
||||
InputMode::Session,
|
||||
KeyWithModifier::new(BareKey::Char('g')).with_ctrl_modifier(),
|
||||
),
|
||||
];
|
||||
let mut keys_to_rebind = vec![
|
||||
(
|
||||
InputMode::Locked,
|
||||
KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier(),
|
||||
vec![actions::Action::SwitchToMode(InputMode::Normal)],
|
||||
),
|
||||
(
|
||||
InputMode::Normal,
|
||||
KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier(),
|
||||
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
||||
),
|
||||
(
|
||||
InputMode::Pane,
|
||||
KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier(),
|
||||
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
||||
),
|
||||
(
|
||||
InputMode::Tab,
|
||||
KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier(),
|
||||
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
||||
),
|
||||
(
|
||||
InputMode::Resize,
|
||||
KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier(),
|
||||
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
||||
),
|
||||
(
|
||||
InputMode::Move,
|
||||
KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier(),
|
||||
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
||||
),
|
||||
(
|
||||
InputMode::Search,
|
||||
KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier(),
|
||||
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
||||
),
|
||||
(
|
||||
InputMode::Session,
|
||||
KeyWithModifier::new(BareKey::Char('a')).with_ctrl_modifier(),
|
||||
vec![actions::Action::SwitchToMode(InputMode::Locked)],
|
||||
),
|
||||
];
|
||||
rebind_keys(keys_to_unbind, keys_to_rebind, write_to_disk);
|
||||
},
|
||||
_ => {},
|
||||
},
|
||||
Event::CustomMessage(message, payload) => {
|
||||
|
|
|
|||
|
|
@ -42,10 +42,11 @@ use zellij_utils::{
|
|||
channels::{self, ChannelWithContext, SenderWithContext},
|
||||
cli::CliArgs,
|
||||
consts::{DEFAULT_SCROLL_BUFFER_SIZE, SCROLL_BUFFER_SIZE},
|
||||
data::{ConnectToSession, Event, InputMode, PluginCapabilities},
|
||||
data::{ConnectToSession, Event, InputMode, KeyWithModifier, PluginCapabilities},
|
||||
errors::{prelude::*, ContextType, ErrorInstruction, FatalError, ServerContext},
|
||||
home::{default_layout_dir, get_default_data_dir},
|
||||
input::{
|
||||
actions::Action,
|
||||
command::{RunCommand, TerminalAction},
|
||||
config::Config,
|
||||
get_mode_info,
|
||||
|
|
@ -109,6 +110,12 @@ pub enum ServerInstruction {
|
|||
},
|
||||
ConfigWrittenToDisk(ClientId, Config),
|
||||
FailedToWriteConfigToDisk(ClientId, Option<PathBuf>), // Pathbuf - file we failed to write
|
||||
RebindKeys {
|
||||
client_id: ClientId,
|
||||
keys_to_rebind: Vec<(InputMode, KeyWithModifier, Vec<Action>)>,
|
||||
keys_to_unbind: Vec<(InputMode, KeyWithModifier)>,
|
||||
write_config_to_disk: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl From<&ServerInstruction> for ServerContext {
|
||||
|
|
@ -145,6 +152,7 @@ impl From<&ServerInstruction> for ServerContext {
|
|||
ServerInstruction::FailedToWriteConfigToDisk(..) => {
|
||||
ServerContext::FailedToWriteConfigToDisk
|
||||
},
|
||||
ServerInstruction::RebindKeys { .. } => ServerContext::RebindKeys,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -226,6 +234,57 @@ impl SessionConfiguration {
|
|||
}
|
||||
(full_reconfigured_config, config_changed)
|
||||
}
|
||||
pub fn rebind_keys(
|
||||
&mut self,
|
||||
client_id: &ClientId,
|
||||
keys_to_rebind: Vec<(InputMode, KeyWithModifier, Vec<Action>)>,
|
||||
keys_to_unbind: Vec<(InputMode, KeyWithModifier)>,
|
||||
) -> (Option<Config>, bool) {
|
||||
let mut full_reconfigured_config = None;
|
||||
let mut config_changed = false;
|
||||
|
||||
if self.runtime_config.get(client_id).is_none() {
|
||||
if let Some(saved_config) = self.saved_config.get(client_id) {
|
||||
self.runtime_config.insert(*client_id, saved_config.clone());
|
||||
}
|
||||
}
|
||||
match self.runtime_config.get_mut(client_id) {
|
||||
Some(config) => {
|
||||
for (input_mode, key_with_modifier) in keys_to_unbind {
|
||||
let keys_in_mode = config
|
||||
.keybinds
|
||||
.0
|
||||
.entry(input_mode)
|
||||
.or_insert_with(Default::default);
|
||||
let removed = keys_in_mode.remove(&key_with_modifier);
|
||||
if removed.is_some() {
|
||||
config_changed = true;
|
||||
}
|
||||
}
|
||||
for (input_mode, key_with_modifier, actions) in keys_to_rebind {
|
||||
let keys_in_mode = config
|
||||
.keybinds
|
||||
.0
|
||||
.entry(input_mode)
|
||||
.or_insert_with(Default::default);
|
||||
if keys_in_mode.get(&key_with_modifier) != Some(&actions) {
|
||||
config_changed = true;
|
||||
keys_in_mode.insert(key_with_modifier, actions);
|
||||
}
|
||||
}
|
||||
if config_changed {
|
||||
full_reconfigured_config = Some(config.clone());
|
||||
}
|
||||
},
|
||||
None => {
|
||||
log::error!(
|
||||
"Could not find runtime or saved configuration for client, cannot rebind keys"
|
||||
);
|
||||
},
|
||||
}
|
||||
|
||||
(full_reconfigured_config, config_changed)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct SessionMetaData {
|
||||
|
|
@ -1120,6 +1179,42 @@ pub fn start_server(mut os_input: Box<dyn ServerOsApi>, socket_path: PathBuf) {
|
|||
.send_to_plugin(PluginInstruction::FailedToWriteConfigToDisk { file_path })
|
||||
.unwrap();
|
||||
},
|
||||
ServerInstruction::RebindKeys {
|
||||
client_id,
|
||||
keys_to_rebind,
|
||||
keys_to_unbind,
|
||||
write_config_to_disk,
|
||||
} => {
|
||||
let (new_config, runtime_config_changed) = session_data
|
||||
.write()
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.session_configuration
|
||||
.rebind_keys(&client_id, keys_to_rebind, keys_to_unbind);
|
||||
if let Some(new_config) = new_config {
|
||||
if write_config_to_disk {
|
||||
let clear_defaults = true;
|
||||
send_to_client!(
|
||||
client_id,
|
||||
os_input,
|
||||
ServerToClientMsg::WriteConfigToDisk {
|
||||
config: new_config.to_string(clear_defaults)
|
||||
},
|
||||
session_state
|
||||
);
|
||||
}
|
||||
|
||||
if runtime_config_changed {
|
||||
session_data
|
||||
.write()
|
||||
.unwrap()
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.propagate_configuration_changes(vec![(client_id, new_config)]);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8470,3 +8470,84 @@ pub fn load_new_plugin_plugin_command() {
|
|||
.count();
|
||||
assert_eq!(request_state_update_requests, 3);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
pub fn rebind_keys_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());
|
||||
let cache_path = plugin_host_folder.join("permissions_test.kdl");
|
||||
let (plugin_thread_sender, server_receiver, screen_receiver, teardown) =
|
||||
create_plugin_thread_with_server_receiver(Some(plugin_host_folder));
|
||||
let plugin_should_float = Some(false);
|
||||
let plugin_title = Some("test_plugin".to_owned());
|
||||
let run_plugin = RunPluginOrAlias::RunPlugin(RunPlugin {
|
||||
_allow_exec_host_cmd: false,
|
||||
location: RunPluginLocation::File(PathBuf::from(&*PLUGIN_FIXTURE)),
|
||||
configuration: Default::default(),
|
||||
..Default::default()
|
||||
});
|
||||
let tab_index = 1;
|
||||
let client_id = 1;
|
||||
let size = Size {
|
||||
cols: 121,
|
||||
rows: 20,
|
||||
};
|
||||
let received_screen_instructions = Arc::new(Mutex::new(vec![]));
|
||||
let _screen_thread = grant_permissions_and_log_actions_in_thread_naked_variant!(
|
||||
received_screen_instructions,
|
||||
ScreenInstruction::Exit,
|
||||
screen_receiver,
|
||||
1,
|
||||
&PermissionType::ChangeApplicationState,
|
||||
cache_path,
|
||||
plugin_thread_sender,
|
||||
client_id
|
||||
);
|
||||
let received_server_instruction = Arc::new(Mutex::new(vec![]));
|
||||
let server_thread = log_actions_in_thread_struct!(
|
||||
received_server_instruction,
|
||||
ServerInstruction::RebindKeys,
|
||||
server_receiver,
|
||||
1
|
||||
);
|
||||
|
||||
let _ = plugin_thread_sender.send(PluginInstruction::AddClient(client_id));
|
||||
let _ = plugin_thread_sender.send(PluginInstruction::Load(
|
||||
plugin_should_float,
|
||||
false,
|
||||
plugin_title,
|
||||
run_plugin,
|
||||
Some(tab_index),
|
||||
None,
|
||||
client_id,
|
||||
size,
|
||||
None,
|
||||
false,
|
||||
));
|
||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||
|
||||
let _ = plugin_thread_sender.send(PluginInstruction::Update(vec![(
|
||||
None,
|
||||
Some(client_id),
|
||||
Event::Key(KeyWithModifier::new(BareKey::Char('y')).with_alt_modifier()), // this triggers the enent in the fixture plugin
|
||||
)]));
|
||||
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_event = received_server_instruction
|
||||
.lock()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|i| {
|
||||
if let ServerInstruction::RebindKeys { .. } = i {
|
||||
Some(i.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.clone();
|
||||
assert_snapshot!(format!("{:#?}", rebind_event));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,231 @@
|
|||
---
|
||||
source: zellij-server/src/plugins/./unit/plugin_tests.rs
|
||||
assertion_line: 6566
|
||||
expression: "format!(\"{:#?}\", rebind_keys_event)"
|
||||
assertion_line: 8552
|
||||
expression: "format!(\"{:#?}\", rebind_event)"
|
||||
---
|
||||
Some(
|
||||
RebindKeys(
|
||||
1,
|
||||
"\n keybinds {\n locked {\n bind \"a\" { NewTab; }\n }\n }\n ",
|
||||
),
|
||||
RebindKeys {
|
||||
client_id: 1,
|
||||
keys_to_rebind: [
|
||||
(
|
||||
Locked,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'a',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
[
|
||||
SwitchToMode(
|
||||
Normal,
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
Normal,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'a',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
[
|
||||
SwitchToMode(
|
||||
Locked,
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
Pane,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'a',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
[
|
||||
SwitchToMode(
|
||||
Locked,
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
Tab,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'a',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
[
|
||||
SwitchToMode(
|
||||
Locked,
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
Resize,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'a',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
[
|
||||
SwitchToMode(
|
||||
Locked,
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
Move,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'a',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
[
|
||||
SwitchToMode(
|
||||
Locked,
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
Search,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'a',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
[
|
||||
SwitchToMode(
|
||||
Locked,
|
||||
),
|
||||
],
|
||||
),
|
||||
(
|
||||
Session,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'a',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
[
|
||||
SwitchToMode(
|
||||
Locked,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
keys_to_unbind: [
|
||||
(
|
||||
Locked,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'g',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
),
|
||||
(
|
||||
Normal,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'g',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
),
|
||||
(
|
||||
Pane,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'g',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
),
|
||||
(
|
||||
Tab,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'g',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
),
|
||||
(
|
||||
Resize,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'g',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
),
|
||||
(
|
||||
Move,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'g',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
),
|
||||
(
|
||||
Search,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'g',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
),
|
||||
(
|
||||
Session,
|
||||
KeyWithModifier {
|
||||
bare_key: Char(
|
||||
'g',
|
||||
),
|
||||
key_modifiers: {
|
||||
Ctrl,
|
||||
},
|
||||
},
|
||||
),
|
||||
],
|
||||
write_config_to_disk: true,
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ use std::{
|
|||
};
|
||||
use wasmtime::{Caller, Linker};
|
||||
use zellij_utils::data::{
|
||||
CommandType, ConnectToSession, FloatingPaneCoordinates, HttpVerb, LayoutInfo, MessageToPlugin,
|
||||
OriginatingPlugin, PermissionStatus, PermissionType, PluginPermission,
|
||||
CommandType, ConnectToSession, FloatingPaneCoordinates, HttpVerb, KeyWithModifier, LayoutInfo,
|
||||
MessageToPlugin, OriginatingPlugin, PermissionStatus, PermissionType, PluginPermission,
|
||||
};
|
||||
use zellij_utils::input::permission::PermissionCache;
|
||||
use zellij_utils::{
|
||||
|
|
@ -346,6 +346,11 @@ fn host_run_plugin_command(caller: Caller<'_, PluginEnv>) {
|
|||
load_in_background,
|
||||
skip_plugin_cache,
|
||||
} => load_new_plugin(env, url, config, load_in_background, skip_plugin_cache),
|
||||
PluginCommand::RebindKeys {
|
||||
keys_to_rebind,
|
||||
keys_to_unbind,
|
||||
write_config_to_disk,
|
||||
} => rebind_keys(env, keys_to_rebind, keys_to_unbind, write_config_to_disk)?,
|
||||
},
|
||||
(PermissionStatus::Denied, permission) => {
|
||||
log::error!(
|
||||
|
|
@ -970,6 +975,25 @@ fn reconfigure(env: &PluginEnv, new_config: String, write_config_to_disk: bool)
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn rebind_keys(
|
||||
env: &PluginEnv,
|
||||
keys_to_rebind: Vec<(InputMode, KeyWithModifier, Vec<Action>)>,
|
||||
keys_to_unbind: Vec<(InputMode, KeyWithModifier)>,
|
||||
write_config_to_disk: bool,
|
||||
) -> Result<()> {
|
||||
let err_context = || "Failed to rebind_keys";
|
||||
let client_id = env.client_id;
|
||||
env.senders
|
||||
.send_to_server(ServerInstruction::RebindKeys {
|
||||
client_id,
|
||||
keys_to_rebind,
|
||||
keys_to_unbind,
|
||||
write_config_to_disk,
|
||||
})
|
||||
.with_context(err_context)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn switch_to_mode(env: &PluginEnv, input_mode: InputMode) {
|
||||
let action = Action::SwitchToMode(input_mode);
|
||||
let error_msg = || format!("failed to switch to mode in plugin {}", env.name());
|
||||
|
|
@ -1874,7 +1898,9 @@ fn check_command_permission(
|
|||
| PluginCommand::CliPipeOutput(..) => PermissionType::ReadCliPipes,
|
||||
PluginCommand::MessageToPlugin(..) => PermissionType::MessageAndLaunchOtherPlugins,
|
||||
PluginCommand::DumpSessionLayout => PermissionType::ReadApplicationState,
|
||||
PluginCommand::Reconfigure(..) => PermissionType::Reconfigure,
|
||||
PluginCommand::RebindKeys { .. } | PluginCommand::Reconfigure(..) => {
|
||||
PermissionType::Reconfigure
|
||||
},
|
||||
_ => return (PermissionStatus::Granted, None),
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use std::{
|
|||
};
|
||||
use zellij_utils::data::*;
|
||||
use zellij_utils::errors::prelude::*;
|
||||
use zellij_utils::input::actions::Action;
|
||||
pub use zellij_utils::plugin_api;
|
||||
use zellij_utils::plugin_api::plugin_command::ProtobufPluginCommand;
|
||||
use zellij_utils::plugin_api::plugin_ids::{ProtobufPluginIds, ProtobufZellijVersion};
|
||||
|
|
@ -853,7 +854,7 @@ pub fn dump_session_layout() {
|
|||
unsafe { host_run_plugin_command() };
|
||||
}
|
||||
|
||||
/// Rebind keys for the current user
|
||||
/// Change configuration for the current user
|
||||
pub fn reconfigure(new_config: String, save_configuration_file: bool) {
|
||||
let plugin_command = PluginCommand::Reconfigure(new_config, save_configuration_file);
|
||||
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
|
||||
|
|
@ -1102,6 +1103,22 @@ pub fn load_new_plugin<S: AsRef<str>>(
|
|||
unsafe { host_run_plugin_command() };
|
||||
}
|
||||
|
||||
/// Rebind keys for the current user
|
||||
pub fn rebind_keys(
|
||||
keys_to_unbind: Vec<(InputMode, KeyWithModifier)>,
|
||||
keys_to_rebind: Vec<(InputMode, KeyWithModifier, Vec<Action>)>,
|
||||
write_config_to_disk: bool,
|
||||
) {
|
||||
let plugin_command = PluginCommand::RebindKeys {
|
||||
keys_to_rebind,
|
||||
keys_to_unbind,
|
||||
write_config_to_disk,
|
||||
};
|
||||
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
|
||||
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
|
||||
unsafe { host_run_plugin_command() };
|
||||
}
|
||||
|
||||
// Utility Functions
|
||||
|
||||
#[allow(unused)]
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ pub struct PluginCommand {
|
|||
pub name: i32,
|
||||
#[prost(
|
||||
oneof = "plugin_command::Payload",
|
||||
tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87"
|
||||
tags = "2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88"
|
||||
)]
|
||||
pub payload: ::core::option::Option<plugin_command::Payload>,
|
||||
}
|
||||
|
|
@ -172,10 +172,40 @@ pub mod plugin_command {
|
|||
ReloadPluginPayload(super::ReloadPluginPayload),
|
||||
#[prost(message, tag = "87")]
|
||||
LoadNewPluginPayload(super::LoadNewPluginPayload),
|
||||
#[prost(message, tag = "88")]
|
||||
RebindKeysPayload(super::RebindKeysPayload),
|
||||
}
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct RebindKeysPayload {
|
||||
#[prost(message, repeated, tag = "1")]
|
||||
pub keys_to_rebind: ::prost::alloc::vec::Vec<KeyToRebind>,
|
||||
#[prost(message, repeated, tag = "2")]
|
||||
pub keys_to_unbind: ::prost::alloc::vec::Vec<KeyToUnbind>,
|
||||
#[prost(bool, tag = "3")]
|
||||
pub write_config_to_disk: bool,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct KeyToRebind {
|
||||
#[prost(enumeration = "super::input_mode::InputMode", tag = "1")]
|
||||
pub input_mode: i32,
|
||||
#[prost(message, optional, tag = "2")]
|
||||
pub key: ::core::option::Option<super::key::Key>,
|
||||
#[prost(message, repeated, tag = "3")]
|
||||
pub actions: ::prost::alloc::vec::Vec<super::action::Action>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct KeyToUnbind {
|
||||
#[prost(enumeration = "super::input_mode::InputMode", tag = "1")]
|
||||
pub input_mode: i32,
|
||||
#[prost(message, optional, tag = "2")]
|
||||
pub key: ::core::option::Option<super::key::Key>,
|
||||
}
|
||||
#[allow(clippy::derive_partial_eq_without_eq)]
|
||||
#[derive(Clone, PartialEq, ::prost::Message)]
|
||||
pub struct LoadNewPluginPayload {
|
||||
#[prost(string, tag = "1")]
|
||||
pub plugin_url: ::prost::alloc::string::String,
|
||||
|
|
@ -684,6 +714,7 @@ pub enum CommandName {
|
|||
BreakPanesToTabWithIndex = 109,
|
||||
ReloadPlugin = 110,
|
||||
LoadNewPlugin = 111,
|
||||
RebindKeys = 112,
|
||||
}
|
||||
impl CommandName {
|
||||
/// String value of the enum field names used in the ProtoBuf definition.
|
||||
|
|
@ -806,6 +837,7 @@ impl CommandName {
|
|||
CommandName::BreakPanesToTabWithIndex => "BreakPanesToTabWithIndex",
|
||||
CommandName::ReloadPlugin => "ReloadPlugin",
|
||||
CommandName::LoadNewPlugin => "LoadNewPlugin",
|
||||
CommandName::RebindKeys => "RebindKeys",
|
||||
}
|
||||
}
|
||||
/// Creates an enum from field names used in the ProtoBuf definition.
|
||||
|
|
@ -925,6 +957,7 @@ impl CommandName {
|
|||
"BreakPanesToTabWithIndex" => Some(Self::BreakPanesToTabWithIndex),
|
||||
"ReloadPlugin" => Some(Self::ReloadPlugin),
|
||||
"LoadNewPlugin" => Some(Self::LoadNewPlugin),
|
||||
"RebindKeys" => Some(Self::RebindKeys),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1873,4 +1873,9 @@ pub enum PluginCommand {
|
|||
load_in_background: bool,
|
||||
skip_plugin_cache: bool,
|
||||
},
|
||||
RebindKeys {
|
||||
keys_to_rebind: Vec<(InputMode, KeyWithModifier, Vec<Action>)>,
|
||||
keys_to_unbind: Vec<(InputMode, KeyWithModifier)>,
|
||||
write_config_to_disk: bool,
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -484,6 +484,7 @@ pub enum ServerContext {
|
|||
Reconfigure,
|
||||
ConfigWrittenToDisk,
|
||||
FailedToWriteConfigToDisk,
|
||||
RebindKeys,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ import "command.proto";
|
|||
import "message.proto";
|
||||
import "resize.proto";
|
||||
import "plugin_permission.proto";
|
||||
import "input_mode.proto";
|
||||
import "key.proto";
|
||||
|
||||
package api.plugin_command;
|
||||
|
||||
|
|
@ -123,6 +125,7 @@ enum CommandName {
|
|||
BreakPanesToTabWithIndex = 109;
|
||||
ReloadPlugin = 110;
|
||||
LoadNewPlugin = 111;
|
||||
RebindKeys = 112;
|
||||
}
|
||||
|
||||
message PluginCommand {
|
||||
|
|
@ -205,9 +208,27 @@ message PluginCommand {
|
|||
BreakPanesToTabWithIndexPayload break_panes_to_tab_with_index_payload = 85;
|
||||
ReloadPluginPayload reload_plugin_payload = 86;
|
||||
LoadNewPluginPayload load_new_plugin_payload = 87;
|
||||
RebindKeysPayload rebind_keys_payload = 88;
|
||||
}
|
||||
}
|
||||
|
||||
message RebindKeysPayload {
|
||||
repeated KeyToRebind keys_to_rebind = 1;
|
||||
repeated KeyToUnbind keys_to_unbind = 2;
|
||||
bool write_config_to_disk = 3;
|
||||
}
|
||||
|
||||
message KeyToRebind {
|
||||
input_mode.InputMode input_mode = 1;
|
||||
key.Key key = 2;
|
||||
repeated action.Action actions = 3;
|
||||
}
|
||||
|
||||
message KeyToUnbind {
|
||||
input_mode.InputMode input_mode = 1;
|
||||
key.Key key = 2;
|
||||
}
|
||||
|
||||
message LoadNewPluginPayload {
|
||||
string plugin_url = 1;
|
||||
repeated ContextItem plugin_config = 2;
|
||||
|
|
|
|||
|
|
@ -9,28 +9,29 @@ pub use super::generated_api::api::{
|
|||
FixedOrPercent as ProtobufFixedOrPercent,
|
||||
FixedOrPercentValue as ProtobufFixedOrPercentValue,
|
||||
FloatingPaneCoordinates as ProtobufFloatingPaneCoordinates, HidePaneWithIdPayload,
|
||||
HttpVerb as ProtobufHttpVerb, IdAndNewName, KillSessionsPayload, LoadNewPluginPayload,
|
||||
MessageToPluginPayload, MovePaneWithPaneIdInDirectionPayload, MovePaneWithPaneIdPayload,
|
||||
MovePayload, NewPluginArgs as ProtobufNewPluginArgs, NewTabsWithLayoutInfoPayload,
|
||||
OpenCommandPanePayload, OpenFilePayload, PageScrollDownInPaneIdPayload,
|
||||
PageScrollUpInPaneIdPayload, PaneId as ProtobufPaneId, PaneType as ProtobufPaneType,
|
||||
PluginCommand as ProtobufPluginCommand, PluginMessagePayload, ReconfigurePayload,
|
||||
ReloadPluginPayload, RequestPluginPermissionPayload, RerunCommandPanePayload,
|
||||
ResizePaneIdWithDirectionPayload, ResizePayload, RunCommandPayload,
|
||||
ScrollDownInPaneIdPayload, ScrollToBottomInPaneIdPayload, ScrollToTopInPaneIdPayload,
|
||||
ScrollUpInPaneIdPayload, SetTimeoutPayload, ShowPaneWithIdPayload, SubscribePayload,
|
||||
SwitchSessionPayload, SwitchTabToPayload, TogglePaneEmbedOrEjectForPaneIdPayload,
|
||||
TogglePaneIdFullscreenPayload, UnsubscribePayload, WebRequestPayload,
|
||||
WriteCharsToPaneIdPayload, WriteToPaneIdPayload,
|
||||
HttpVerb as ProtobufHttpVerb, IdAndNewName, KeyToRebind, KeyToUnbind, KillSessionsPayload,
|
||||
LoadNewPluginPayload, MessageToPluginPayload, MovePaneWithPaneIdInDirectionPayload,
|
||||
MovePaneWithPaneIdPayload, MovePayload, NewPluginArgs as ProtobufNewPluginArgs,
|
||||
NewTabsWithLayoutInfoPayload, OpenCommandPanePayload, OpenFilePayload,
|
||||
PageScrollDownInPaneIdPayload, PageScrollUpInPaneIdPayload, PaneId as ProtobufPaneId,
|
||||
PaneType as ProtobufPaneType, PluginCommand as ProtobufPluginCommand, PluginMessagePayload,
|
||||
RebindKeysPayload, ReconfigurePayload, ReloadPluginPayload, RequestPluginPermissionPayload,
|
||||
RerunCommandPanePayload, ResizePaneIdWithDirectionPayload, ResizePayload,
|
||||
RunCommandPayload, ScrollDownInPaneIdPayload, ScrollToBottomInPaneIdPayload,
|
||||
ScrollToTopInPaneIdPayload, ScrollUpInPaneIdPayload, SetTimeoutPayload,
|
||||
ShowPaneWithIdPayload, SubscribePayload, SwitchSessionPayload, SwitchTabToPayload,
|
||||
TogglePaneEmbedOrEjectForPaneIdPayload, TogglePaneIdFullscreenPayload, UnsubscribePayload,
|
||||
WebRequestPayload, WriteCharsToPaneIdPayload, WriteToPaneIdPayload,
|
||||
},
|
||||
plugin_permission::PermissionType as ProtobufPermissionType,
|
||||
resize::ResizeAction as ProtobufResizeAction,
|
||||
};
|
||||
|
||||
use crate::data::{
|
||||
ConnectToSession, FloatingPaneCoordinates, HttpVerb, MessageToPlugin, NewPluginArgs, PaneId,
|
||||
PermissionType, PluginCommand,
|
||||
ConnectToSession, FloatingPaneCoordinates, HttpVerb, InputMode, KeyWithModifier,
|
||||
MessageToPlugin, NewPluginArgs, PaneId, PermissionType, PluginCommand,
|
||||
};
|
||||
use crate::input::actions::Action;
|
||||
use crate::input::layout::SplitSize;
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
|
|
@ -184,6 +185,60 @@ impl TryFrom<PaneId> for ProtobufPaneId {
|
|||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(InputMode, KeyWithModifier, Vec<Action>)> for KeyToRebind {
|
||||
type Error = &'static str;
|
||||
fn try_from(
|
||||
key_to_rebind: (InputMode, KeyWithModifier, Vec<Action>),
|
||||
) -> Result<Self, &'static str> {
|
||||
Ok(KeyToRebind {
|
||||
input_mode: key_to_rebind.0 as i32,
|
||||
key: Some(key_to_rebind.1.try_into()?),
|
||||
actions: key_to_rebind
|
||||
.2
|
||||
.into_iter()
|
||||
.filter_map(|a| a.try_into().ok())
|
||||
.collect(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(InputMode, KeyWithModifier)> for KeyToUnbind {
|
||||
type Error = &'static str;
|
||||
fn try_from(key_to_unbind: (InputMode, KeyWithModifier)) -> Result<Self, &'static str> {
|
||||
Ok(KeyToUnbind {
|
||||
input_mode: key_to_unbind.0 as i32,
|
||||
key: Some(key_to_unbind.1.try_into()?),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn key_to_rebind_to_plugin_command_assets(
|
||||
key_to_rebind: KeyToRebind,
|
||||
) -> Option<(InputMode, KeyWithModifier, Vec<Action>)> {
|
||||
Some((
|
||||
ProtobufInputMode::from_i32(key_to_rebind.input_mode)?
|
||||
.try_into()
|
||||
.ok()?,
|
||||
key_to_rebind.key?.try_into().ok()?,
|
||||
key_to_rebind
|
||||
.actions
|
||||
.into_iter()
|
||||
.filter_map(|a| a.try_into().ok())
|
||||
.collect(),
|
||||
))
|
||||
}
|
||||
|
||||
fn key_to_unbind_to_plugin_command_assets(
|
||||
key_to_unbind: KeyToUnbind,
|
||||
) -> Option<(InputMode, KeyWithModifier)> {
|
||||
Some((
|
||||
ProtobufInputMode::from_i32(key_to_unbind.input_mode)?
|
||||
.try_into()
|
||||
.ok()?,
|
||||
key_to_unbind.key?.try_into().ok()?,
|
||||
))
|
||||
}
|
||||
|
||||
impl TryFrom<ProtobufPluginCommand> for PluginCommand {
|
||||
type Error = &'static str;
|
||||
fn try_from(protobuf_plugin_command: ProtobufPluginCommand) -> Result<Self, &'static str> {
|
||||
|
|
@ -1226,6 +1281,24 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
|
|||
},
|
||||
_ => Err("Mismatched payload for LoadNewPlugin"),
|
||||
},
|
||||
Some(CommandName::RebindKeys) => match protobuf_plugin_command.payload {
|
||||
Some(Payload::RebindKeysPayload(rebind_keys_payload)) => {
|
||||
Ok(PluginCommand::RebindKeys {
|
||||
keys_to_rebind: rebind_keys_payload
|
||||
.keys_to_rebind
|
||||
.into_iter()
|
||||
.filter_map(|k| key_to_rebind_to_plugin_command_assets(k))
|
||||
.collect(),
|
||||
keys_to_unbind: rebind_keys_payload
|
||||
.keys_to_unbind
|
||||
.into_iter()
|
||||
.filter_map(|k| key_to_unbind_to_plugin_command_assets(k))
|
||||
.collect(),
|
||||
write_config_to_disk: rebind_keys_payload.write_config_to_disk,
|
||||
})
|
||||
},
|
||||
_ => Err("Mismatched payload for RebindKeys"),
|
||||
},
|
||||
None => Err("Unrecognized plugin command"),
|
||||
}
|
||||
}
|
||||
|
|
@ -2031,6 +2104,24 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
|
|||
should_load_plugin_in_background: load_in_background,
|
||||
})),
|
||||
}),
|
||||
PluginCommand::RebindKeys {
|
||||
keys_to_rebind,
|
||||
keys_to_unbind,
|
||||
write_config_to_disk,
|
||||
} => Ok(ProtobufPluginCommand {
|
||||
name: CommandName::RebindKeys as i32,
|
||||
payload: Some(Payload::RebindKeysPayload(RebindKeysPayload {
|
||||
keys_to_rebind: keys_to_rebind
|
||||
.into_iter()
|
||||
.filter_map(|k| k.try_into().ok())
|
||||
.collect(),
|
||||
keys_to_unbind: keys_to_unbind
|
||||
.into_iter()
|
||||
.filter_map(|k| k.try_into().ok())
|
||||
.collect(),
|
||||
write_config_to_disk,
|
||||
})),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue