feat(plugins): add API to open new tabs with a LayoutInfo (#3305)

* feat(plugins): add api to open new tabs with a layout info

* fix tests
This commit is contained in:
Aram Drevekenin 2024-04-26 11:38:39 +02:00 committed by GitHub
parent cd37864b38
commit 7562a81f0d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 130 additions and 6 deletions

View file

@ -978,12 +978,14 @@ fn init_session(
let client_attributes = client_attributes.clone(); let client_attributes = client_attributes.clone();
let default_shell = default_shell.clone(); let default_shell = default_shell.clone();
let capabilities = capabilities.clone(); let capabilities = capabilities.clone();
let layout_dir = config_options.layout_dir.clone();
move || { move || {
plugin_thread_main( plugin_thread_main(
plugin_bus, plugin_bus,
store, store,
data_dir, data_dir,
layout, layout,
layout_dir,
path_to_default_shell, path_to_default_shell,
zellij_cwd, zellij_cwd,
capabilities, capabilities,

View file

@ -190,6 +190,7 @@ pub(crate) fn plugin_thread_main(
store: Store, store: Store,
data_dir: PathBuf, data_dir: PathBuf,
mut layout: Box<Layout>, mut layout: Box<Layout>,
layout_dir: Option<PathBuf>,
path_to_default_shell: PathBuf, path_to_default_shell: PathBuf,
zellij_cwd: PathBuf, zellij_cwd: PathBuf,
capabilities: PluginCapabilities, capabilities: PluginCapabilities,
@ -217,6 +218,7 @@ pub(crate) fn plugin_thread_main(
client_attributes, client_attributes,
default_shell, default_shell,
layout.clone(), layout.clone(),
layout_dir,
); );
loop { loop {

View file

@ -66,6 +66,7 @@ pub struct PluginLoader<'a> {
client_attributes: ClientAttributes, client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>, default_shell: Option<TerminalAction>,
default_layout: Box<Layout>, default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
} }
impl<'a> PluginLoader<'a> { impl<'a> PluginLoader<'a> {
@ -84,6 +85,7 @@ impl<'a> PluginLoader<'a> {
client_attributes: ClientAttributes, client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>, default_shell: Option<TerminalAction>,
default_layout: Box<Layout>, default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
) -> 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> =
@ -108,6 +110,7 @@ impl<'a> PluginLoader<'a> {
client_attributes, client_attributes,
default_shell, default_shell,
default_layout, default_layout,
layout_dir,
)?; )?;
plugin_loader plugin_loader
.load_module_from_memory() .load_module_from_memory()
@ -149,6 +152,7 @@ impl<'a> PluginLoader<'a> {
default_shell: Option<TerminalAction>, default_shell: Option<TerminalAction>,
default_layout: Box<Layout>, default_layout: Box<Layout>,
skip_cache: bool, skip_cache: bool,
layout_dir: Option<PathBuf>,
) -> 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(
@ -168,6 +172,7 @@ impl<'a> PluginLoader<'a> {
client_attributes, client_attributes,
default_shell, default_shell,
default_layout, default_layout,
layout_dir,
)?; )?;
if skip_cache { if skip_cache {
plugin_loader plugin_loader
@ -231,6 +236,7 @@ impl<'a> PluginLoader<'a> {
client_attributes: ClientAttributes, client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>, default_shell: Option<TerminalAction>,
default_layout: Box<Layout>, default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
) -> 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() {
@ -252,6 +258,7 @@ impl<'a> PluginLoader<'a> {
client_attributes.clone(), client_attributes.clone(),
default_shell.clone(), default_shell.clone(),
default_layout.clone(), default_layout.clone(),
layout_dir.clone(),
)?; )?;
plugin_loader plugin_loader
.load_module_from_memory() .load_module_from_memory()
@ -285,6 +292,7 @@ impl<'a> PluginLoader<'a> {
client_attributes: ClientAttributes, client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>, default_shell: Option<TerminalAction>,
default_layout: Box<Layout>, default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
) -> Result<()> { ) -> Result<()> {
let err_context = || format!("failed to reload plugin id {plugin_id}"); let err_context = || format!("failed to reload plugin id {plugin_id}");
@ -310,6 +318,7 @@ impl<'a> PluginLoader<'a> {
client_attributes, client_attributes,
default_shell, default_shell,
default_layout, default_layout,
layout_dir,
)?; )?;
plugin_loader plugin_loader
.compile_module() .compile_module()
@ -347,6 +356,7 @@ impl<'a> PluginLoader<'a> {
client_attributes: ClientAttributes, client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>, default_shell: Option<TerminalAction>,
default_layout: Box<Layout>, default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
) -> 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())
@ -373,6 +383,7 @@ impl<'a> PluginLoader<'a> {
client_attributes, client_attributes,
default_shell, default_shell,
default_layout, default_layout,
layout_dir,
}) })
} }
pub fn new_from_existing_plugin_attributes( pub fn new_from_existing_plugin_attributes(
@ -390,6 +401,7 @@ impl<'a> PluginLoader<'a> {
client_attributes: ClientAttributes, client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>, default_shell: Option<TerminalAction>,
default_layout: Box<Layout>, default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
) -> 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) = {
@ -423,6 +435,7 @@ impl<'a> PluginLoader<'a> {
client_attributes, client_attributes,
default_shell, default_shell,
default_layout, default_layout,
layout_dir,
) )
} }
pub fn new_from_different_client_id( pub fn new_from_different_client_id(
@ -440,6 +453,7 @@ impl<'a> PluginLoader<'a> {
client_attributes: ClientAttributes, client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>, default_shell: Option<TerminalAction>,
default_layout: Box<Layout>, default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
) -> 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 = {
@ -474,6 +488,7 @@ impl<'a> PluginLoader<'a> {
client_attributes, client_attributes,
default_shell, default_shell,
default_layout, default_layout,
layout_dir,
) )
} }
pub fn load_module_from_memory(&mut self) -> Result<Module> { pub fn load_module_from_memory(&mut self) -> Result<Module> {
@ -737,6 +752,7 @@ impl<'a> PluginLoader<'a> {
self.client_attributes.clone(), self.client_attributes.clone(),
self.default_shell.clone(), self.default_shell.clone(),
self.default_layout.clone(), self.default_layout.clone(),
self.layout_dir.clone(),
)?; )?;
plugin_loader_for_client plugin_loader_for_client
.load_module_from_memory() .load_module_from_memory()
@ -845,6 +861,7 @@ impl<'a> PluginLoader<'a> {
plugin_cwd: self.zellij_cwd.clone(), plugin_cwd: self.zellij_cwd.clone(),
input_pipes_to_unblock: Arc::new(Mutex::new(HashSet::new())), input_pipes_to_unblock: Arc::new(Mutex::new(HashSet::new())),
input_pipes_to_block: Arc::new(Mutex::new(HashSet::new())), input_pipes_to_block: Arc::new(Mutex::new(HashSet::new())),
layout_dir: self.layout_dir.clone(),
}; };
let subscriptions = Arc::new(Mutex::new(HashSet::new())); let subscriptions = Arc::new(Mutex::new(HashSet::new()));

View file

@ -278,6 +278,7 @@ pub struct PluginEnv {
pub client_attributes: ClientAttributes, pub client_attributes: ClientAttributes,
pub default_shell: Option<TerminalAction>, pub default_shell: Option<TerminalAction>,
pub default_layout: Box<Layout>, pub default_layout: Box<Layout>,
pub layout_dir: Option<PathBuf>,
pub plugin_cwd: PathBuf, pub plugin_cwd: PathBuf,
pub input_pipes_to_unblock: Arc<Mutex<HashSet<String>>>, pub input_pipes_to_unblock: Arc<Mutex<HashSet<String>>>,
pub input_pipes_to_block: Arc<Mutex<HashSet<String>>>, pub input_pipes_to_block: Arc<Mutex<HashSet<String>>>,

View file

@ -271,6 +271,7 @@ fn create_plugin_thread(
store, store,
data_dir, data_dir,
Box::new(Layout::default()), Box::new(Layout::default()),
None,
default_shell, default_shell,
zellij_cwd, zellij_cwd,
plugin_capabilities, plugin_capabilities,
@ -349,6 +350,7 @@ fn create_plugin_thread_with_server_receiver(
store, store,
data_dir, data_dir,
Box::new(Layout::default()), Box::new(Layout::default()),
None,
default_shell, default_shell,
zellij_cwd, zellij_cwd,
plugin_capabilities, plugin_capabilities,
@ -433,6 +435,7 @@ fn create_plugin_thread_with_pty_receiver(
store, store,
data_dir, data_dir,
Box::new(Layout::default()), Box::new(Layout::default()),
None,
default_shell, default_shell,
zellij_cwd, zellij_cwd,
plugin_capabilities, plugin_capabilities,
@ -512,6 +515,7 @@ fn create_plugin_thread_with_background_jobs_receiver(
store, store,
data_dir, data_dir,
Box::new(Layout::default()), Box::new(Layout::default()),
None,
default_shell, default_shell,
zellij_cwd, zellij_cwd,
plugin_capabilities, plugin_capabilities,

View file

@ -101,6 +101,7 @@ pub struct WasmBridge {
cached_plugin_map: cached_plugin_map:
HashMap<RunPluginLocation, HashMap<PluginUserConfiguration, Vec<(PluginId, ClientId)>>>, HashMap<RunPluginLocation, HashMap<PluginUserConfiguration, Vec<(PluginId, ClientId)>>>,
pending_pipes: PendingPipes, pending_pipes: PendingPipes,
layout_dir: Option<PathBuf>,
} }
impl WasmBridge { impl WasmBridge {
@ -114,6 +115,7 @@ impl WasmBridge {
client_attributes: ClientAttributes, client_attributes: ClientAttributes,
default_shell: Option<TerminalAction>, default_shell: Option<TerminalAction>,
default_layout: Box<Layout>, default_layout: Box<Layout>,
layout_dir: Option<PathBuf>,
) -> Self { ) -> Self {
let plugin_map = Arc::new(Mutex::new(PluginMap::default())); let plugin_map = Arc::new(Mutex::new(PluginMap::default()));
let connected_clients: Arc<Mutex<Vec<ClientId>>> = Arc::new(Mutex::new(vec![])); let connected_clients: Arc<Mutex<Vec<ClientId>>> = Arc::new(Mutex::new(vec![]));
@ -143,6 +145,7 @@ impl WasmBridge {
default_layout, default_layout,
cached_plugin_map: HashMap::new(), cached_plugin_map: HashMap::new(),
pending_pipes: Default::default(), pending_pipes: Default::default(),
layout_dir,
} }
} }
pub fn load_plugin( pub fn load_plugin(
@ -198,6 +201,7 @@ impl WasmBridge {
let client_attributes = self.client_attributes.clone(); let client_attributes = self.client_attributes.clone();
let default_shell = self.default_shell.clone(); let default_shell = self.default_shell.clone();
let default_layout = self.default_layout.clone(); let default_layout = self.default_layout.clone();
let layout_dir = self.layout_dir.clone();
async move { async move {
let _ = senders.send_to_background_jobs( let _ = senders.send_to_background_jobs(
BackgroundJob::AnimatePluginLoading(plugin_id), BackgroundJob::AnimatePluginLoading(plugin_id),
@ -244,6 +248,7 @@ impl WasmBridge {
default_shell, default_shell,
default_layout, default_layout,
skip_cache, skip_cache,
layout_dir,
) { ) {
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(
@ -334,6 +339,7 @@ impl WasmBridge {
let client_attributes = self.client_attributes.clone(); let client_attributes = self.client_attributes.clone();
let default_shell = self.default_shell.clone(); let default_shell = self.default_shell.clone();
let default_layout = self.default_layout.clone(); let default_layout = self.default_layout.clone();
let layout_dir = self.layout_dir.clone();
async move { async move {
match PluginLoader::reload_plugin( match PluginLoader::reload_plugin(
first_plugin_id, first_plugin_id,
@ -350,6 +356,7 @@ impl WasmBridge {
client_attributes.clone(), client_attributes.clone(),
default_shell.clone(), default_shell.clone(),
default_layout.clone(), default_layout.clone(),
layout_dir.clone(),
) { ) {
Ok(_) => { Ok(_) => {
handle_plugin_successful_loading(&senders, first_plugin_id); handle_plugin_successful_loading(&senders, first_plugin_id);
@ -374,6 +381,7 @@ impl WasmBridge {
client_attributes.clone(), client_attributes.clone(),
default_shell.clone(), default_shell.clone(),
default_layout.clone(), default_layout.clone(),
layout_dir.clone(),
) { ) {
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(
@ -425,6 +433,7 @@ impl WasmBridge {
self.client_attributes.clone(), self.client_attributes.clone(),
self.default_shell.clone(), self.default_shell.clone(),
self.default_layout.clone(), self.default_layout.clone(),
self.layout_dir.clone(),
) { ) {
Ok(_) => { Ok(_) => {
let _ = self let _ = self

View file

@ -154,6 +154,9 @@ fn host_run_plugin_command(env: FunctionEnvMut<ForeignFunctionEnv>) {
PluginCommand::NewTabsWithLayout(raw_layout) => { PluginCommand::NewTabsWithLayout(raw_layout) => {
new_tabs_with_layout(env, &raw_layout)? new_tabs_with_layout(env, &raw_layout)?
}, },
PluginCommand::NewTabsWithLayoutInfo(layout_info) => {
new_tabs_with_layout_info(env, layout_info)?
},
PluginCommand::NewTab => new_tab(env), PluginCommand::NewTab => new_tab(env),
PluginCommand::GoToNextTab => go_to_next_tab(env), PluginCommand::GoToNextTab => go_to_next_tab(env),
PluginCommand::GoToPreviousTab => go_to_previous_tab(env), PluginCommand::GoToPreviousTab => go_to_previous_tab(env),
@ -859,6 +862,19 @@ fn new_tabs_with_layout(env: &ForeignFunctionEnv, raw_layout: &str) -> Result<()
None, None,
) )
.map_err(|e| anyhow!("Failed to parse layout: {:?}", e))?; .map_err(|e| anyhow!("Failed to parse layout: {:?}", e))?;
apply_layout(env, layout);
Ok(())
}
fn new_tabs_with_layout_info(env: &ForeignFunctionEnv, layout_info: LayoutInfo) -> Result<()> {
// TODO: cwd
let layout = Layout::from_layout_info(&env.plugin_env.layout_dir, layout_info)
.map_err(|e| anyhow!("Failed to parse layout: {:?}", e))?;
apply_layout(env, layout);
Ok(())
}
fn apply_layout(env: &ForeignFunctionEnv, layout: Layout) {
let mut tabs_to_open = vec![]; let mut tabs_to_open = vec![];
let tabs = layout.tabs(); let tabs = layout.tabs();
if tabs.is_empty() { if tabs.is_empty() {
@ -890,7 +906,6 @@ fn new_tabs_with_layout(env: &ForeignFunctionEnv, raw_layout: &str) -> Result<()
let error_msg = || format!("Failed to create layout tab"); let error_msg = || format!("Failed to create layout tab");
apply_action!(action, error_msg, env); apply_action!(action, error_msg, env);
} }
Ok(())
} }
fn new_tab(env: &ForeignFunctionEnv) { fn new_tab(env: &ForeignFunctionEnv) {
@ -1526,6 +1541,7 @@ fn check_command_permission(
PluginCommand::SwitchTabTo(..) PluginCommand::SwitchTabTo(..)
| PluginCommand::SwitchToMode(..) | PluginCommand::SwitchToMode(..)
| PluginCommand::NewTabsWithLayout(..) | PluginCommand::NewTabsWithLayout(..)
| PluginCommand::NewTabsWithLayoutInfo(..)
| PluginCommand::NewTab | PluginCommand::NewTab
| PluginCommand::GoToNextTab | PluginCommand::GoToNextTab
| PluginCommand::GoToPreviousTab | PluginCommand::GoToPreviousTab

View file

@ -273,6 +273,14 @@ pub fn new_tabs_with_layout(layout: &str) {
unsafe { host_run_plugin_command() }; unsafe { host_run_plugin_command() };
} }
/// Provide a LayoutInfo to be applied to the current session in a new tab. If the layout has multiple tabs, they will all be opened.
pub fn new_tabs_with_layout_info(layout_info: LayoutInfo) {
let plugin_command = PluginCommand::NewTabsWithLayoutInfo(layout_info);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() };
}
/// Open a new tab with the default layout /// Open a new tab with the default layout
pub fn new_tab() { pub fn new_tab() {
let plugin_command = PluginCommand::NewTab; let plugin_command = PluginCommand::NewTab;

View file

@ -5,7 +5,7 @@ pub struct PluginCommand {
pub name: i32, pub name: i32,
#[prost( #[prost(
oneof = "plugin_command::Payload", 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" 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"
)] )]
pub payload: ::core::option::Option<plugin_command::Payload>, pub payload: ::core::option::Option<plugin_command::Payload>,
} }
@ -116,10 +116,18 @@ pub mod plugin_command {
KillSessionsPayload(super::KillSessionsPayload), KillSessionsPayload(super::KillSessionsPayload),
#[prost(string, tag = "61")] #[prost(string, tag = "61")]
ScanHostFolderPayload(::prost::alloc::string::String), ScanHostFolderPayload(::prost::alloc::string::String),
#[prost(message, tag = "62")]
NewTabsWithLayoutInfoPayload(super::NewTabsWithLayoutInfoPayload),
} }
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
pub struct NewTabsWithLayoutInfoPayload {
#[prost(message, optional, tag = "1")]
pub layout_info: ::core::option::Option<super::event::LayoutInfo>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct KillSessionsPayload { pub struct KillSessionsPayload {
#[prost(string, repeated, tag = "1")] #[prost(string, repeated, tag = "1")]
pub session_names: ::prost::alloc::vec::Vec<::prost::alloc::string::String>, pub session_names: ::prost::alloc::vec::Vec<::prost::alloc::string::String>,
@ -422,6 +430,7 @@ pub enum CommandName {
WatchFilesystem = 83, WatchFilesystem = 83,
DumpSessionLayout = 84, DumpSessionLayout = 84,
CloseSelf = 85, CloseSelf = 85,
NewTabsWithLayoutInfo = 86,
} }
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.
@ -516,6 +525,7 @@ impl CommandName {
CommandName::WatchFilesystem => "WatchFilesystem", CommandName::WatchFilesystem => "WatchFilesystem",
CommandName::DumpSessionLayout => "DumpSessionLayout", CommandName::DumpSessionLayout => "DumpSessionLayout",
CommandName::CloseSelf => "CloseSelf", CommandName::CloseSelf => "CloseSelf",
CommandName::NewTabsWithLayoutInfo => "NewTabsWithLayoutInfo",
} }
} }
/// Creates an enum from field names used in the ProtoBuf definition. /// Creates an enum from field names used in the ProtoBuf definition.
@ -607,6 +617,7 @@ impl CommandName {
"WatchFilesystem" => Some(Self::WatchFilesystem), "WatchFilesystem" => Some(Self::WatchFilesystem),
"DumpSessionLayout" => Some(Self::DumpSessionLayout), "DumpSessionLayout" => Some(Self::DumpSessionLayout),
"CloseSelf" => Some(Self::CloseSelf), "CloseSelf" => Some(Self::CloseSelf),
"NewTabsWithLayoutInfo" => Some(Self::NewTabsWithLayoutInfo),
_ => None, _ => None,
} }
} }

View file

@ -1380,4 +1380,5 @@ pub enum PluginCommand {
WatchFilesystem, WatchFilesystem,
DumpSessionLayout, DumpSessionLayout,
CloseSelf, CloseSelf,
NewTabsWithLayoutInfo(LayoutInfo),
} }

View file

@ -1075,7 +1075,6 @@ impl Default for LayoutParts {
} }
impl Layout { impl Layout {
// the first layout will either be the default one
pub fn list_available_layouts( pub fn list_available_layouts(
layout_dir: Option<PathBuf>, layout_dir: Option<PathBuf>,
default_layout_name: &Option<String>, default_layout_name: &Option<String>,
@ -1131,6 +1130,31 @@ impl Layout {
}); });
available_layouts available_layouts
} }
pub fn from_layout_info(
layout_dir: &Option<PathBuf>,
layout_info: LayoutInfo,
) -> Result<Layout, ConfigError> {
let (path_to_raw_layout, raw_layout, raw_swap_layouts) = match layout_info {
LayoutInfo::File(layout_name_without_extension) => {
let layout_dir = layout_dir.clone().or_else(|| default_layout_dir());
Self::stringified_from_dir(
&PathBuf::from(layout_name_without_extension),
layout_dir.as_ref(),
)?
},
LayoutInfo::BuiltIn(layout_name) => {
Self::stringified_from_default_assets(&PathBuf::from(layout_name))?
},
};
Layout::from_kdl(
&raw_layout,
path_to_raw_layout,
raw_swap_layouts
.as_ref()
.map(|(r, f)| (r.as_str(), f.as_str())),
None,
)
}
pub fn stringified_from_path_or_default( pub fn stringified_from_path_or_default(
layout_path: Option<&PathBuf>, layout_path: Option<&PathBuf>,
layout_dir: Option<PathBuf>, layout_dir: Option<PathBuf>,

View file

@ -97,6 +97,7 @@ enum CommandName {
WatchFilesystem = 83; WatchFilesystem = 83;
DumpSessionLayout = 84; DumpSessionLayout = 84;
CloseSelf = 85; CloseSelf = 85;
NewTabsWithLayoutInfo = 86;
} }
message PluginCommand { message PluginCommand {
@ -153,9 +154,14 @@ message PluginCommand {
MessageToPluginPayload message_to_plugin_payload = 50; MessageToPluginPayload message_to_plugin_payload = 50;
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;
} }
} }
message NewTabsWithLayoutInfoPayload {
event.LayoutInfo layout_info = 1;
}
message KillSessionsPayload { message KillSessionsPayload {
repeated string session_names = 1; repeated string session_names = 1;
} }

View file

@ -8,9 +8,9 @@ pub use super::generated_api::api::{
FixedOrPercentValue as ProtobufFixedOrPercentValue, FixedOrPercentValue as ProtobufFixedOrPercentValue,
FloatingPaneCoordinates as ProtobufFloatingPaneCoordinates, HttpVerb as ProtobufHttpVerb, FloatingPaneCoordinates as ProtobufFloatingPaneCoordinates, HttpVerb as ProtobufHttpVerb,
IdAndNewName, KillSessionsPayload, MessageToPluginPayload, MovePayload, IdAndNewName, KillSessionsPayload, MessageToPluginPayload, MovePayload,
NewPluginArgs as ProtobufNewPluginArgs, OpenCommandPanePayload, OpenFilePayload, NewPluginArgs as ProtobufNewPluginArgs, NewTabsWithLayoutInfoPayload,
PaneId as ProtobufPaneId, PaneType as ProtobufPaneType, OpenCommandPanePayload, OpenFilePayload, PaneId as ProtobufPaneId,
PluginCommand as ProtobufPluginCommand, PluginMessagePayload, PaneType as ProtobufPaneType, PluginCommand as ProtobufPluginCommand, PluginMessagePayload,
RequestPluginPermissionPayload, ResizePayload, RunCommandPayload, SetTimeoutPayload, RequestPluginPermissionPayload, ResizePayload, RunCommandPayload, SetTimeoutPayload,
SubscribePayload, SwitchSessionPayload, SwitchTabToPayload, UnsubscribePayload, SubscribePayload, SwitchSessionPayload, SwitchTabToPayload, UnsubscribePayload,
WebRequestPayload, WebRequestPayload,
@ -875,6 +875,19 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
Some(_) => Err("CloseSelf should have no payload, found a payload"), Some(_) => Err("CloseSelf should have no payload, found a payload"),
None => Ok(PluginCommand::CloseSelf), None => Ok(PluginCommand::CloseSelf),
}, },
Some(CommandName::NewTabsWithLayoutInfo) => match protobuf_plugin_command.payload {
Some(Payload::NewTabsWithLayoutInfoPayload(new_tabs_with_layout_info_payload)) => {
new_tabs_with_layout_info_payload
.layout_info
.and_then(|layout_info| {
Some(PluginCommand::NewTabsWithLayoutInfo(
layout_info.try_into().ok()?,
))
})
.ok_or("Failed to parse NewTabsWithLayoutInfo command")
},
_ => Err("Mismatched payload for NewTabsWithLayoutInfo"),
},
None => Err("Unrecognized plugin command"), None => Err("Unrecognized plugin command"),
} }
} }
@ -1397,6 +1410,16 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
name: CommandName::CloseSelf as i32, name: CommandName::CloseSelf as i32,
payload: None, payload: None,
}), }),
PluginCommand::NewTabsWithLayoutInfo(new_tabs_with_layout_info_payload) => {
Ok(ProtobufPluginCommand {
name: CommandName::NewTabsWithLayoutInfo as i32,
payload: Some(Payload::NewTabsWithLayoutInfoPayload(
NewTabsWithLayoutInfoPayload {
layout_info: new_tabs_with_layout_info_payload.try_into().ok(),
},
)),
})
},
} }
} }
} }