mirror of
https://github.com/zellij-org/zellij.git
synced 2026-10-11 22:50:07 +00:00
5220 lines
224 KiB
Rust
5220 lines
224 KiB
Rust
use std::str::FromStr;
|
|
|
|
use crate::data::ClientId;
|
|
|
|
use crate::{
|
|
client_server_contract::client_server_contract::{
|
|
client_to_server_msg, server_to_client_msg, ActionMsg, AttachClientMsg,
|
|
AttachWatcherClientMsg, BackgroundColorMsg, CliPipeOutputMsg, ClientExitedMsg,
|
|
ClientToServerMsg as ProtoClientToServerMsg, ColorRegistersMsg, ConfigFileUpdatedMsg,
|
|
ConnStatusMsg, ConnectedMsg, DesktopNotificationResponseMsg, DetachSessionMsg,
|
|
EmitNestedSessionFrameMsg, ExitMsg, ExitReason as ProtoExitReason,
|
|
FailedToStartWebServerMsg, FirstClientConnectedMsg, ForegroundColorMsg,
|
|
ForwardQueryToHostMsg, ForwardedReplyFromHostMsg, HostTerminalFocusChangedMsg,
|
|
HostTerminalThemeChangedMsg,
|
|
HostTerminalThemeIndication as ProtoHostTerminalThemeIndication,
|
|
InputMode as ProtoInputMode, KeyMsg, KillSessionMsg, KittyGraphicsSupportMsg,
|
|
KittyZlibSupportMsg, LayoutMetadata as ProtoLayoutMetadata, LogErrorMsg, LogMsg,
|
|
MobileActivePaneMsg, MobilePaneMsg, MobileRenderPrefsMsg, MobileSessionMsg, MobileSizeMsg,
|
|
MobileStateMsg, MobileTabMsg, NestedSessionFrameFromHostMsg,
|
|
PaneMetadata as ProtoPaneMetadata, PaneRenderUpdateMsg, QueryTerminalSizeMsg,
|
|
RenamedSessionMsg, RenderMsg, RequestSessionListMsg,
|
|
ServerToClientMsg as ProtoServerToClientMsg, SetMobileRenderPreferencesMsg,
|
|
SetSoftKeyboardMsg, SixelSupportMsg, SoftKeyboardVisibilityChangedMsg, StartWebServerMsg,
|
|
SubscribeToPaneRendersMsg, SubscribedPaneClosedMsg, SwitchSessionMsg,
|
|
TabMetadata as ProtoTabMetadata, TerminalPixelDimensionsMsg, TerminalResizeMsg,
|
|
UnblockCliPipeInputMsg, UnblockInputThreadMsg, WebServerStartedMsg,
|
|
},
|
|
data::{HostTerminalThemeMode, InputMode, PaneId},
|
|
errors::prelude::*,
|
|
ipc::{
|
|
ClientToServerMsg, ColorRegister, ExitReason, MobileActivePanePayload, MobilePanePayload,
|
|
MobileRenderPrefsPayload, MobileSessionPayload, MobileSizePayload, MobileStatePayload,
|
|
MobileTabPayload, PaneReference, PixelDimensions, ServerToClientMsg,
|
|
},
|
|
};
|
|
use std::collections::BTreeMap;
|
|
use std::path::PathBuf;
|
|
|
|
// Convert Rust ClientToServerMsg to protobuf
|
|
impl From<ClientToServerMsg> for ProtoClientToServerMsg {
|
|
fn from(msg: ClientToServerMsg) -> Self {
|
|
let message = match msg {
|
|
ClientToServerMsg::DetachSession { client_ids } => {
|
|
client_to_server_msg::Message::DetachSession(DetachSessionMsg {
|
|
client_ids: client_ids.into_iter().map(|id| id as u32).collect(),
|
|
})
|
|
},
|
|
ClientToServerMsg::TerminalPixelDimensions { pixel_dimensions } => {
|
|
client_to_server_msg::Message::TerminalPixelDimensions(TerminalPixelDimensionsMsg {
|
|
pixel_dimensions: Some(pixel_dimensions.into()),
|
|
})
|
|
},
|
|
ClientToServerMsg::BackgroundColor { color } => {
|
|
client_to_server_msg::Message::BackgroundColor(BackgroundColorMsg { color })
|
|
},
|
|
ClientToServerMsg::ForegroundColor { color } => {
|
|
client_to_server_msg::Message::ForegroundColor(ForegroundColorMsg { color })
|
|
},
|
|
ClientToServerMsg::ColorRegisters { color_registers } => {
|
|
client_to_server_msg::Message::ColorRegisters(ColorRegistersMsg {
|
|
color_registers: color_registers.into_iter().map(|cr| cr.into()).collect(),
|
|
})
|
|
},
|
|
ClientToServerMsg::TerminalResize { new_size } => {
|
|
client_to_server_msg::Message::TerminalResize(TerminalResizeMsg {
|
|
new_size: Some(new_size.into()),
|
|
})
|
|
},
|
|
ClientToServerMsg::FirstClientConnected {
|
|
cli_assets,
|
|
is_web_client,
|
|
} => client_to_server_msg::Message::FirstClientConnected(FirstClientConnectedMsg {
|
|
cli_assets: Some(cli_assets.into()),
|
|
is_web_client,
|
|
}),
|
|
ClientToServerMsg::AttachClient {
|
|
cli_assets,
|
|
tab_position_to_focus,
|
|
pane_to_focus,
|
|
is_web_client,
|
|
} => client_to_server_msg::Message::AttachClient(AttachClientMsg {
|
|
cli_assets: Some(cli_assets.into()),
|
|
tab_position_to_focus: tab_position_to_focus.map(|pos| pos as u32),
|
|
pane_to_focus: pane_to_focus.map(|p| p.into()),
|
|
is_web_client,
|
|
}),
|
|
ClientToServerMsg::AttachWatcherClient {
|
|
terminal_size,
|
|
is_web_client,
|
|
} => client_to_server_msg::Message::AttachWatcherClient(AttachWatcherClientMsg {
|
|
terminal_size: Some(terminal_size.into()),
|
|
is_web_client,
|
|
}),
|
|
ClientToServerMsg::Action {
|
|
action,
|
|
terminal_id,
|
|
client_id,
|
|
is_cli_client,
|
|
} => client_to_server_msg::Message::Action(ActionMsg {
|
|
action: Some(action.into()),
|
|
terminal_id,
|
|
client_id: client_id.map(|id| id as u32),
|
|
is_cli_client,
|
|
}),
|
|
ClientToServerMsg::Key {
|
|
key,
|
|
raw_bytes,
|
|
is_kitty_keyboard_protocol,
|
|
} => client_to_server_msg::Message::Key(KeyMsg {
|
|
key: Some(key.into()),
|
|
raw_bytes: raw_bytes.into_iter().map(|b| b as u32).collect(),
|
|
is_kitty_keyboard_protocol,
|
|
}),
|
|
ClientToServerMsg::ClientExited => {
|
|
client_to_server_msg::Message::ClientExited(ClientExitedMsg {})
|
|
},
|
|
ClientToServerMsg::KillSession => {
|
|
client_to_server_msg::Message::KillSession(KillSessionMsg {})
|
|
},
|
|
ClientToServerMsg::ConnStatus => {
|
|
client_to_server_msg::Message::ConnStatus(ConnStatusMsg {})
|
|
},
|
|
ClientToServerMsg::WebServerStarted { base_url } => {
|
|
client_to_server_msg::Message::WebServerStarted(WebServerStartedMsg { base_url })
|
|
},
|
|
ClientToServerMsg::FailedToStartWebServer { error } => {
|
|
client_to_server_msg::Message::FailedToStartWebServer(FailedToStartWebServerMsg {
|
|
error,
|
|
})
|
|
},
|
|
ClientToServerMsg::SubscribeToPaneRenders {
|
|
pane_ids,
|
|
scrollback,
|
|
ansi,
|
|
} => client_to_server_msg::Message::SubscribeToPaneRenders(SubscribeToPaneRendersMsg {
|
|
pane_ids: pane_ids.into_iter().map(|id| id.into()).collect(),
|
|
scrollback: scrollback.map(|s| s as u32),
|
|
ansi,
|
|
}),
|
|
ClientToServerMsg::DesktopNotificationResponse { raw_bytes } => {
|
|
client_to_server_msg::Message::DesktopNotificationResponse(
|
|
DesktopNotificationResponseMsg { raw_bytes },
|
|
)
|
|
},
|
|
ClientToServerMsg::ForwardedReplyFromHost { token, reply_bytes } => {
|
|
client_to_server_msg::Message::ForwardedReplyFromHost(ForwardedReplyFromHostMsg {
|
|
token,
|
|
reply_bytes,
|
|
})
|
|
},
|
|
ClientToServerMsg::HostTerminalThemeChanged { mode } => {
|
|
let proto_mode: ProtoHostTerminalThemeIndication = mode.into();
|
|
client_to_server_msg::Message::HostTerminalThemeChanged(
|
|
HostTerminalThemeChangedMsg {
|
|
mode: proto_mode as i32,
|
|
},
|
|
)
|
|
},
|
|
ClientToServerMsg::SoftKeyboardVisibilityChanged { visible } => {
|
|
client_to_server_msg::Message::SoftKeyboardVisibilityChanged(
|
|
SoftKeyboardVisibilityChangedMsg { visible },
|
|
)
|
|
},
|
|
ClientToServerMsg::NestedSessionFrameFromHost { payload_bytes } => {
|
|
client_to_server_msg::Message::NestedSessionFrameFromHost(
|
|
NestedSessionFrameFromHostMsg { payload_bytes },
|
|
)
|
|
},
|
|
ClientToServerMsg::KittyGraphicsSupport { supported } => {
|
|
client_to_server_msg::Message::KittyGraphicsSupport(KittyGraphicsSupportMsg {
|
|
supported,
|
|
})
|
|
},
|
|
ClientToServerMsg::KittyZlibSupport { supported } => {
|
|
client_to_server_msg::Message::KittyZlibSupport(KittyZlibSupportMsg { supported })
|
|
},
|
|
ClientToServerMsg::SixelSupport { supported } => {
|
|
client_to_server_msg::Message::SixelSupport(SixelSupportMsg { supported })
|
|
},
|
|
ClientToServerMsg::RequestSessionList => {
|
|
client_to_server_msg::Message::RequestSessionList(RequestSessionListMsg {})
|
|
},
|
|
ClientToServerMsg::SetMobileRenderPreferences { single_pane, fit } => {
|
|
client_to_server_msg::Message::SetMobileRenderPreferences(
|
|
SetMobileRenderPreferencesMsg { single_pane, fit },
|
|
)
|
|
},
|
|
ClientToServerMsg::HostTerminalFocusChanged { focused } => {
|
|
client_to_server_msg::Message::HostTerminalFocusChanged(
|
|
HostTerminalFocusChangedMsg { focused },
|
|
)
|
|
},
|
|
};
|
|
|
|
ProtoClientToServerMsg {
|
|
message: Some(message),
|
|
}
|
|
}
|
|
}
|
|
|
|
// Convert protobuf ClientToServerMsg to Rust
|
|
impl TryFrom<ProtoClientToServerMsg> for ClientToServerMsg {
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(msg: ProtoClientToServerMsg) -> Result<Self> {
|
|
match msg.message {
|
|
Some(client_to_server_msg::Message::DetachSession(detach)) => {
|
|
Ok(ClientToServerMsg::DetachSession {
|
|
client_ids: detach
|
|
.client_ids
|
|
.into_iter()
|
|
.map(|id| id as ClientId)
|
|
.collect(),
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::TerminalPixelDimensions(pixel_dims)) => {
|
|
Ok(ClientToServerMsg::TerminalPixelDimensions {
|
|
pixel_dimensions: pixel_dims
|
|
.pixel_dimensions
|
|
.ok_or_else(|| anyhow!("Missing pixel_dimensions"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::BackgroundColor(bg_color)) => {
|
|
Ok(ClientToServerMsg::BackgroundColor {
|
|
color: bg_color.color,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::ForegroundColor(fg_color)) => {
|
|
Ok(ClientToServerMsg::ForegroundColor {
|
|
color: fg_color.color,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::ColorRegisters(color_regs)) => {
|
|
Ok(ClientToServerMsg::ColorRegisters {
|
|
color_registers: color_regs
|
|
.color_registers
|
|
.into_iter()
|
|
.map(|cr| cr.try_into())
|
|
.collect::<Result<Vec<_>>>()?,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::TerminalResize(resize)) => {
|
|
Ok(ClientToServerMsg::TerminalResize {
|
|
new_size: resize
|
|
.new_size
|
|
.ok_or_else(|| anyhow!("Missing new_size"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::FirstClientConnected(first_client)) => {
|
|
Ok(ClientToServerMsg::FirstClientConnected {
|
|
cli_assets: first_client
|
|
.cli_assets
|
|
.ok_or_else(|| anyhow!("Missing cli_assets"))?
|
|
.try_into()?,
|
|
is_web_client: first_client.is_web_client,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::AttachClient(attach)) => {
|
|
Ok(ClientToServerMsg::AttachClient {
|
|
cli_assets: attach
|
|
.cli_assets
|
|
.ok_or_else(|| anyhow!("Missing cli_assets"))?
|
|
.try_into()?,
|
|
tab_position_to_focus: attach.tab_position_to_focus.map(|pos| pos as usize),
|
|
pane_to_focus: attach.pane_to_focus.map(|p| p.try_into()).transpose()?,
|
|
is_web_client: attach.is_web_client,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::AttachWatcherClient(attach_watcher)) => {
|
|
Ok(ClientToServerMsg::AttachWatcherClient {
|
|
terminal_size: attach_watcher
|
|
.terminal_size
|
|
.ok_or_else(|| anyhow::anyhow!("Missing terminal_size"))?
|
|
.try_into()?,
|
|
is_web_client: attach_watcher.is_web_client,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::Action(action)) => Ok(ClientToServerMsg::Action {
|
|
action: action
|
|
.action
|
|
.ok_or_else(|| anyhow!("Missing action"))?
|
|
.try_into()?,
|
|
terminal_id: action.terminal_id,
|
|
client_id: action.client_id.map(|id| id as ClientId),
|
|
is_cli_client: action.is_cli_client,
|
|
}),
|
|
Some(client_to_server_msg::Message::Key(key)) => Ok(ClientToServerMsg::Key {
|
|
key: key.key.ok_or_else(|| anyhow!("Missing key"))?.try_into()?,
|
|
raw_bytes: key.raw_bytes.into_iter().map(|b| b as u8).collect(),
|
|
is_kitty_keyboard_protocol: key.is_kitty_keyboard_protocol,
|
|
}),
|
|
Some(client_to_server_msg::Message::ClientExited(_)) => {
|
|
Ok(ClientToServerMsg::ClientExited)
|
|
},
|
|
Some(client_to_server_msg::Message::KillSession(_)) => {
|
|
Ok(ClientToServerMsg::KillSession)
|
|
},
|
|
Some(client_to_server_msg::Message::ConnStatus(_)) => Ok(ClientToServerMsg::ConnStatus),
|
|
Some(client_to_server_msg::Message::WebServerStarted(web_server)) => {
|
|
Ok(ClientToServerMsg::WebServerStarted {
|
|
base_url: web_server.base_url,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::FailedToStartWebServer(failed)) => {
|
|
Ok(ClientToServerMsg::FailedToStartWebServer {
|
|
error: failed.error,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::SubscribeToPaneRenders(msg)) => {
|
|
let pane_ids: Result<Vec<PaneId>> =
|
|
msg.pane_ids.into_iter().map(|p| p.try_into()).collect();
|
|
Ok(ClientToServerMsg::SubscribeToPaneRenders {
|
|
pane_ids: pane_ids?,
|
|
scrollback: msg.scrollback.map(|s| s as usize),
|
|
ansi: msg.ansi,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::DesktopNotificationResponse(msg)) => {
|
|
Ok(ClientToServerMsg::DesktopNotificationResponse {
|
|
raw_bytes: msg.raw_bytes,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::ForwardedReplyFromHost(msg)) => {
|
|
Ok(ClientToServerMsg::ForwardedReplyFromHost {
|
|
token: msg.token,
|
|
reply_bytes: msg.reply_bytes,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::HostTerminalThemeChanged(msg)) => {
|
|
let proto_mode = ProtoHostTerminalThemeIndication::try_from(msg.mode)
|
|
.ok()
|
|
.ok_or_else(|| anyhow!("Unknown HostTerminalThemeIndication: {}", msg.mode))?;
|
|
Ok(ClientToServerMsg::HostTerminalThemeChanged {
|
|
mode: proto_mode.into(),
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::SoftKeyboardVisibilityChanged(msg)) => {
|
|
Ok(ClientToServerMsg::SoftKeyboardVisibilityChanged {
|
|
visible: msg.visible,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::NestedSessionFrameFromHost(msg)) => {
|
|
Ok(ClientToServerMsg::NestedSessionFrameFromHost {
|
|
payload_bytes: msg.payload_bytes,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::KittyGraphicsSupport(msg)) => {
|
|
Ok(ClientToServerMsg::KittyGraphicsSupport {
|
|
supported: msg.supported,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::KittyZlibSupport(msg)) => {
|
|
Ok(ClientToServerMsg::KittyZlibSupport {
|
|
supported: msg.supported,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::SixelSupport(msg)) => {
|
|
Ok(ClientToServerMsg::SixelSupport {
|
|
supported: msg.supported,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::RequestSessionList(_)) => {
|
|
Ok(ClientToServerMsg::RequestSessionList)
|
|
},
|
|
Some(client_to_server_msg::Message::SetMobileRenderPreferences(msg)) => {
|
|
Ok(ClientToServerMsg::SetMobileRenderPreferences {
|
|
single_pane: msg.single_pane,
|
|
fit: msg.fit,
|
|
})
|
|
},
|
|
Some(client_to_server_msg::Message::HostTerminalFocusChanged(msg)) => {
|
|
Ok(ClientToServerMsg::HostTerminalFocusChanged {
|
|
focused: msg.focused,
|
|
})
|
|
},
|
|
None => Err(anyhow!("Empty ClientToServerMsg message")),
|
|
}
|
|
}
|
|
}
|
|
|
|
// Convert Rust ServerToClientMsg to protobuf
|
|
impl From<ServerToClientMsg> for ProtoServerToClientMsg {
|
|
fn from(msg: ServerToClientMsg) -> Self {
|
|
let message = match msg {
|
|
ServerToClientMsg::Render { content } => {
|
|
server_to_client_msg::Message::Render(RenderMsg { content })
|
|
},
|
|
ServerToClientMsg::UnblockInputThread => {
|
|
server_to_client_msg::Message::UnblockInputThread(UnblockInputThreadMsg {})
|
|
},
|
|
ServerToClientMsg::Exit { exit_reason } => {
|
|
let (proto_exit_reason, payload) = match exit_reason {
|
|
ExitReason::Error(ref msg) => (ProtoExitReason::Error, Some(msg.clone())),
|
|
ExitReason::CustomExitStatus(status) => {
|
|
(ProtoExitReason::CustomExitStatus, Some(status.to_string()))
|
|
},
|
|
other => (ProtoExitReason::from(other), None),
|
|
};
|
|
server_to_client_msg::Message::Exit(ExitMsg {
|
|
exit_reason: proto_exit_reason as i32,
|
|
payload,
|
|
})
|
|
},
|
|
ServerToClientMsg::Connected => {
|
|
server_to_client_msg::Message::Connected(ConnectedMsg {})
|
|
},
|
|
ServerToClientMsg::Log { lines } => {
|
|
server_to_client_msg::Message::Log(LogMsg { lines })
|
|
},
|
|
ServerToClientMsg::LogError { lines } => {
|
|
server_to_client_msg::Message::LogError(LogErrorMsg { lines })
|
|
},
|
|
ServerToClientMsg::SwitchSession { connect_to_session } => {
|
|
server_to_client_msg::Message::SwitchSession(SwitchSessionMsg {
|
|
connect_to_session: Some(connect_to_session.into()),
|
|
})
|
|
},
|
|
ServerToClientMsg::UnblockCliPipeInput {
|
|
pipe_name,
|
|
exit_code,
|
|
} => server_to_client_msg::Message::UnblockCliPipeInput(UnblockCliPipeInputMsg {
|
|
pipe_name,
|
|
exit_code,
|
|
}),
|
|
ServerToClientMsg::CliPipeOutput { pipe_name, output } => {
|
|
server_to_client_msg::Message::CliPipeOutput(CliPipeOutputMsg { pipe_name, output })
|
|
},
|
|
ServerToClientMsg::QueryTerminalSize => {
|
|
server_to_client_msg::Message::QueryTerminalSize(QueryTerminalSizeMsg {})
|
|
},
|
|
ServerToClientMsg::StartWebServer => {
|
|
server_to_client_msg::Message::StartWebServer(StartWebServerMsg {})
|
|
},
|
|
ServerToClientMsg::RenamedSession { name } => {
|
|
server_to_client_msg::Message::RenamedSession(RenamedSessionMsg { name })
|
|
},
|
|
ServerToClientMsg::ConfigFileUpdated => {
|
|
server_to_client_msg::Message::ConfigFileUpdated(ConfigFileUpdatedMsg {})
|
|
},
|
|
ServerToClientMsg::PaneRenderUpdate {
|
|
pane_id,
|
|
viewport,
|
|
scrollback,
|
|
is_initial,
|
|
} => server_to_client_msg::Message::PaneRenderUpdate(PaneRenderUpdateMsg {
|
|
pane_id: Some(pane_id.into()),
|
|
viewport,
|
|
scrollback: scrollback.clone().unwrap_or_default(),
|
|
has_scrollback: scrollback.is_some(),
|
|
is_initial,
|
|
}),
|
|
ServerToClientMsg::SubscribedPaneClosed { pane_id } => {
|
|
server_to_client_msg::Message::SubscribedPaneClosed(SubscribedPaneClosedMsg {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
ServerToClientMsg::ForwardQueryToHost {
|
|
token,
|
|
query_bytes,
|
|
resolve_async,
|
|
} => server_to_client_msg::Message::ForwardQueryToHost(ForwardQueryToHostMsg {
|
|
token,
|
|
query_bytes,
|
|
resolve_async,
|
|
}),
|
|
ServerToClientMsg::SetSoftKeyboard { on } => {
|
|
server_to_client_msg::Message::SetSoftKeyboard(SetSoftKeyboardMsg { on })
|
|
},
|
|
ServerToClientMsg::EmitNestedSessionFrame { payload_bytes } => {
|
|
server_to_client_msg::Message::EmitNestedSessionFrame(EmitNestedSessionFrameMsg {
|
|
payload_bytes,
|
|
})
|
|
},
|
|
ServerToClientMsg::MobileState { payload } => {
|
|
server_to_client_msg::Message::MobileState(mobile_state_payload_to_proto(payload))
|
|
},
|
|
};
|
|
|
|
ProtoServerToClientMsg {
|
|
message: Some(message),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn mobile_state_payload_to_proto(payload: MobileStatePayload) -> MobileStateMsg {
|
|
MobileStateMsg {
|
|
session_name: payload.session_name,
|
|
now_secs: payload.now_secs,
|
|
is_welcome_screen: payload.is_welcome_screen,
|
|
desktop_client_connected: payload.desktop_client_connected,
|
|
desktop_size: payload.desktop_size.map(|s| MobileSizeMsg {
|
|
cols: s.cols as u32,
|
|
rows: s.rows as u32,
|
|
}),
|
|
active_pane: payload.active_pane.map(|p| MobileActivePaneMsg {
|
|
pane_id: p.pane_id,
|
|
is_plugin: p.is_plugin,
|
|
tab_position: p.tab_position as u32,
|
|
}),
|
|
tabs: payload
|
|
.tabs
|
|
.into_iter()
|
|
.map(|t| MobileTabMsg {
|
|
position: t.position as u32,
|
|
name: t.name,
|
|
active: t.active,
|
|
})
|
|
.collect(),
|
|
panes: payload
|
|
.panes
|
|
.into_iter()
|
|
.map(|p| MobilePaneMsg {
|
|
tab_position: p.tab_position as u32,
|
|
pane_id: p.pane_id,
|
|
is_plugin: p.is_plugin,
|
|
title: p.title,
|
|
is_floating: p.is_floating,
|
|
last_activity_secs_ago: p.last_activity_secs_ago,
|
|
})
|
|
.collect(),
|
|
sessions: payload
|
|
.sessions
|
|
.into_iter()
|
|
.map(|s| MobileSessionMsg {
|
|
name: s.name,
|
|
web_clients_allowed: s.web_clients_allowed,
|
|
tab_count: s.tab_count as u32,
|
|
pane_count: s.pane_count as u32,
|
|
connected_clients: s.connected_clients as u32,
|
|
creation_secs_ago: s.creation_secs_ago,
|
|
})
|
|
.collect(),
|
|
render_prefs: Some(MobileRenderPrefsMsg {
|
|
single_pane: payload.render_prefs.single_pane,
|
|
fit: payload.render_prefs.fit,
|
|
active_pane_is_fullscreen: payload.render_prefs.active_pane_is_fullscreen,
|
|
}),
|
|
}
|
|
}
|
|
|
|
fn mobile_state_payload_from_proto(msg: MobileStateMsg) -> MobileStatePayload {
|
|
MobileStatePayload {
|
|
session_name: msg.session_name,
|
|
now_secs: msg.now_secs,
|
|
is_welcome_screen: msg.is_welcome_screen,
|
|
desktop_client_connected: msg.desktop_client_connected,
|
|
desktop_size: msg.desktop_size.map(|s| MobileSizePayload {
|
|
cols: s.cols as usize,
|
|
rows: s.rows as usize,
|
|
}),
|
|
active_pane: msg.active_pane.map(|p| MobileActivePanePayload {
|
|
pane_id: p.pane_id,
|
|
is_plugin: p.is_plugin,
|
|
tab_position: p.tab_position as usize,
|
|
}),
|
|
tabs: msg
|
|
.tabs
|
|
.into_iter()
|
|
.map(|t| MobileTabPayload {
|
|
position: t.position as usize,
|
|
name: t.name,
|
|
active: t.active,
|
|
})
|
|
.collect(),
|
|
panes: msg
|
|
.panes
|
|
.into_iter()
|
|
.map(|p| MobilePanePayload {
|
|
tab_position: p.tab_position as usize,
|
|
pane_id: p.pane_id,
|
|
is_plugin: p.is_plugin,
|
|
title: p.title,
|
|
is_floating: p.is_floating,
|
|
last_activity_secs_ago: p.last_activity_secs_ago,
|
|
})
|
|
.collect(),
|
|
sessions: msg
|
|
.sessions
|
|
.into_iter()
|
|
.map(|s| MobileSessionPayload {
|
|
name: s.name,
|
|
web_clients_allowed: s.web_clients_allowed,
|
|
tab_count: s.tab_count as usize,
|
|
pane_count: s.pane_count as usize,
|
|
connected_clients: s.connected_clients as usize,
|
|
creation_secs_ago: s.creation_secs_ago,
|
|
})
|
|
.collect(),
|
|
render_prefs: msg
|
|
.render_prefs
|
|
.map(|p| MobileRenderPrefsPayload {
|
|
single_pane: p.single_pane,
|
|
fit: p.fit,
|
|
active_pane_is_fullscreen: p.active_pane_is_fullscreen,
|
|
})
|
|
.unwrap_or(MobileRenderPrefsPayload {
|
|
single_pane: true,
|
|
fit: true,
|
|
active_pane_is_fullscreen: false,
|
|
}),
|
|
}
|
|
}
|
|
|
|
// Convert protobuf ServerToClientMsg to Rust
|
|
impl TryFrom<ProtoServerToClientMsg> for ServerToClientMsg {
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(msg: ProtoServerToClientMsg) -> Result<Self> {
|
|
match msg.message {
|
|
Some(server_to_client_msg::Message::Render(render)) => Ok(ServerToClientMsg::Render {
|
|
content: render.content,
|
|
}),
|
|
Some(server_to_client_msg::Message::UnblockInputThread(_)) => {
|
|
Ok(ServerToClientMsg::UnblockInputThread)
|
|
},
|
|
Some(server_to_client_msg::Message::Exit(exit)) => {
|
|
let proto_exit_reason = ProtoExitReason::try_from(exit.exit_reason)
|
|
.ok()
|
|
.ok_or_else(|| anyhow!("Invalid exit_reason"))?;
|
|
|
|
let exit_reason = match proto_exit_reason {
|
|
ProtoExitReason::Error => {
|
|
let error_msg =
|
|
exit.payload.unwrap_or_else(|| "Protobuf error".to_string());
|
|
ExitReason::Error(error_msg)
|
|
},
|
|
ProtoExitReason::CustomExitStatus => {
|
|
let status_str = exit.payload.unwrap_or_else(|| "0".to_string());
|
|
let status = status_str
|
|
.parse::<i32>()
|
|
.map_err(|_| anyhow!("Invalid custom exit status: {}", status_str))?;
|
|
ExitReason::CustomExitStatus(status)
|
|
},
|
|
other => other.try_into()?,
|
|
};
|
|
|
|
Ok(ServerToClientMsg::Exit { exit_reason })
|
|
},
|
|
Some(server_to_client_msg::Message::Connected(_)) => Ok(ServerToClientMsg::Connected),
|
|
Some(server_to_client_msg::Message::Log(log)) => {
|
|
Ok(ServerToClientMsg::Log { lines: log.lines })
|
|
},
|
|
Some(server_to_client_msg::Message::LogError(log_error)) => {
|
|
Ok(ServerToClientMsg::LogError {
|
|
lines: log_error.lines,
|
|
})
|
|
},
|
|
Some(server_to_client_msg::Message::SwitchSession(switch)) => {
|
|
Ok(ServerToClientMsg::SwitchSession {
|
|
connect_to_session: switch
|
|
.connect_to_session
|
|
.ok_or_else(|| anyhow!("Missing connect_to_session"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
Some(server_to_client_msg::Message::UnblockCliPipeInput(unblock)) => {
|
|
Ok(ServerToClientMsg::UnblockCliPipeInput {
|
|
pipe_name: unblock.pipe_name,
|
|
exit_code: unblock.exit_code,
|
|
})
|
|
},
|
|
Some(server_to_client_msg::Message::CliPipeOutput(pipe_output)) => {
|
|
Ok(ServerToClientMsg::CliPipeOutput {
|
|
pipe_name: pipe_output.pipe_name,
|
|
output: pipe_output.output,
|
|
})
|
|
},
|
|
Some(server_to_client_msg::Message::QueryTerminalSize(_)) => {
|
|
Ok(ServerToClientMsg::QueryTerminalSize)
|
|
},
|
|
Some(server_to_client_msg::Message::StartWebServer(_)) => {
|
|
Ok(ServerToClientMsg::StartWebServer)
|
|
},
|
|
Some(server_to_client_msg::Message::RenamedSession(renamed)) => {
|
|
Ok(ServerToClientMsg::RenamedSession { name: renamed.name })
|
|
},
|
|
Some(server_to_client_msg::Message::ConfigFileUpdated(_)) => {
|
|
Ok(ServerToClientMsg::ConfigFileUpdated)
|
|
},
|
|
Some(server_to_client_msg::Message::PaneRenderUpdate(msg)) => {
|
|
let pane_id: PaneId = msg
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("Missing pane_id"))?
|
|
.try_into()?;
|
|
let scrollback = if msg.has_scrollback {
|
|
Some(msg.scrollback)
|
|
} else {
|
|
None
|
|
};
|
|
Ok(ServerToClientMsg::PaneRenderUpdate {
|
|
pane_id,
|
|
viewport: msg.viewport,
|
|
scrollback,
|
|
is_initial: msg.is_initial,
|
|
})
|
|
},
|
|
Some(server_to_client_msg::Message::SubscribedPaneClosed(msg)) => {
|
|
let pane_id: PaneId = msg
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("Missing pane_id"))?
|
|
.try_into()?;
|
|
Ok(ServerToClientMsg::SubscribedPaneClosed { pane_id })
|
|
},
|
|
Some(server_to_client_msg::Message::ForwardQueryToHost(msg)) => {
|
|
Ok(ServerToClientMsg::ForwardQueryToHost {
|
|
token: msg.token,
|
|
query_bytes: msg.query_bytes,
|
|
resolve_async: msg.resolve_async,
|
|
})
|
|
},
|
|
Some(server_to_client_msg::Message::SetSoftKeyboard(msg)) => {
|
|
Ok(ServerToClientMsg::SetSoftKeyboard { on: msg.on })
|
|
},
|
|
Some(server_to_client_msg::Message::EmitNestedSessionFrame(msg)) => {
|
|
Ok(ServerToClientMsg::EmitNestedSessionFrame {
|
|
payload_bytes: msg.payload_bytes,
|
|
})
|
|
},
|
|
Some(server_to_client_msg::Message::MobileState(msg)) => {
|
|
Ok(ServerToClientMsg::MobileState {
|
|
payload: mobile_state_payload_from_proto(msg),
|
|
})
|
|
},
|
|
None => Err(anyhow!("Empty ServerToClientMsg message")),
|
|
}
|
|
}
|
|
}
|
|
|
|
// Basic type conversions
|
|
impl From<crate::pane_size::Size> for crate::client_server_contract::client_server_contract::Size {
|
|
fn from(size: crate::pane_size::Size) -> Self {
|
|
Self {
|
|
cols: size.cols as u32,
|
|
rows: size.rows as u32,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::Size>
|
|
for crate::pane_size::Size
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(size: crate::client_server_contract::client_server_contract::Size) -> Result<Self> {
|
|
Ok(Self {
|
|
rows: size.rows as usize,
|
|
cols: size.cols as usize,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<PixelDimensions>
|
|
for crate::client_server_contract::client_server_contract::PixelDimensions
|
|
{
|
|
fn from(pixel_dims: PixelDimensions) -> Self {
|
|
Self {
|
|
text_area_size: pixel_dims.text_area_size.map(|size| {
|
|
crate::client_server_contract::client_server_contract::SizeInPixels {
|
|
width: size.width as u32,
|
|
height: size.height as u32,
|
|
}
|
|
}),
|
|
character_cell_size: pixel_dims.character_cell_size.map(|size| {
|
|
crate::client_server_contract::client_server_contract::SizeInPixels {
|
|
width: size.width as u32,
|
|
height: size.height as u32,
|
|
}
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::PixelDimensions>
|
|
for PixelDimensions
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
pixel_dims: crate::client_server_contract::client_server_contract::PixelDimensions,
|
|
) -> Result<Self> {
|
|
Ok(Self {
|
|
text_area_size: pixel_dims
|
|
.text_area_size
|
|
.map(|size| crate::pane_size::SizeInPixels {
|
|
width: size.width as usize,
|
|
height: size.height as usize,
|
|
}),
|
|
character_cell_size: pixel_dims.character_cell_size.map(|size| {
|
|
crate::pane_size::SizeInPixels {
|
|
width: size.width as usize,
|
|
height: size.height as usize,
|
|
}
|
|
}),
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<PaneReference> for crate::client_server_contract::client_server_contract::PaneReference {
|
|
fn from(pane_ref: PaneReference) -> Self {
|
|
Self {
|
|
pane_id: pane_ref.pane_id,
|
|
is_plugin: pane_ref.is_plugin,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::PaneReference>
|
|
for PaneReference
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
pane_ref: crate::client_server_contract::client_server_contract::PaneReference,
|
|
) -> Result<Self> {
|
|
Ok(Self {
|
|
pane_id: pane_ref.pane_id,
|
|
is_plugin: pane_ref.is_plugin,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<ColorRegister> for crate::client_server_contract::client_server_contract::ColorRegister {
|
|
fn from(color_reg: ColorRegister) -> Self {
|
|
Self {
|
|
index: color_reg.index as u32,
|
|
color: color_reg.color,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::ColorRegister>
|
|
for ColorRegister
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
color_reg: crate::client_server_contract::client_server_contract::ColorRegister,
|
|
) -> Result<Self> {
|
|
Ok(Self {
|
|
index: color_reg.index as usize,
|
|
color: color_reg.color,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<crate::input::cli_assets::CliAssets>
|
|
for crate::client_server_contract::client_server_contract::CliAssets
|
|
{
|
|
fn from(cli_assets: crate::input::cli_assets::CliAssets) -> Self {
|
|
Self {
|
|
config_file_path: cli_assets
|
|
.config_file_path
|
|
.map(|p| p.to_string_lossy().to_string()),
|
|
config_dir: cli_assets
|
|
.config_dir
|
|
.map(|p| p.to_string_lossy().to_string()),
|
|
should_ignore_config: cli_assets.should_ignore_config,
|
|
configuration_options: cli_assets.configuration_options.map(|o| o.into()),
|
|
layout: cli_assets.layout.map(|l| l.into()),
|
|
terminal_window_size: Some(cli_assets.terminal_window_size.into()),
|
|
data_dir: cli_assets.data_dir.map(|p| p.to_string_lossy().to_string()),
|
|
is_debug: cli_assets.is_debug,
|
|
max_panes: cli_assets.max_panes.map(|m| m as u32),
|
|
force_run_layout_commands: cli_assets.force_run_layout_commands,
|
|
cwd: cli_assets.cwd.map(|p| p.to_string_lossy().to_string()),
|
|
host_terminal_env: cli_assets.host_terminal_env.into_iter().collect(),
|
|
initial_panes: cli_assets
|
|
.initial_panes
|
|
.map(|panes| panes.into_iter().map(|p| p.into()).collect())
|
|
.unwrap_or_default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::CliAssets>
|
|
for crate::input::cli_assets::CliAssets
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
cli_assets: crate::client_server_contract::client_server_contract::CliAssets,
|
|
) -> Result<Self> {
|
|
Ok(Self {
|
|
config_file_path: cli_assets.config_file_path.map(PathBuf::from),
|
|
config_dir: cli_assets.config_dir.map(PathBuf::from),
|
|
should_ignore_config: cli_assets.should_ignore_config,
|
|
configuration_options: cli_assets
|
|
.configuration_options
|
|
.map(|o| o.try_into())
|
|
.transpose()?,
|
|
layout: cli_assets.layout.map(|l| l.try_into()).transpose()?,
|
|
terminal_window_size: cli_assets
|
|
.terminal_window_size
|
|
.ok_or_else(|| anyhow!("CliAssets missing terminal_window_size"))?
|
|
.try_into()?,
|
|
data_dir: cli_assets.data_dir.map(PathBuf::from),
|
|
is_debug: cli_assets.is_debug,
|
|
max_panes: cli_assets.max_panes.map(|m| m as usize),
|
|
force_run_layout_commands: cli_assets.force_run_layout_commands,
|
|
cwd: cli_assets.cwd.map(PathBuf::from),
|
|
host_terminal_env: cli_assets.host_terminal_env.into_iter().collect(),
|
|
initial_panes: if cli_assets.initial_panes.is_empty() {
|
|
None
|
|
} else {
|
|
Some(
|
|
cli_assets
|
|
.initial_panes
|
|
.into_iter()
|
|
.map(|p| p.try_into())
|
|
.collect::<Result<Vec<_>>>()?,
|
|
)
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<crate::input::options::Options>
|
|
for crate::client_server_contract::client_server_contract::Options
|
|
{
|
|
fn from(options: crate::input::options::Options) -> Self {
|
|
use crate::client_server_contract::client_server_contract::{
|
|
Clipboard as ProtoClipboard, OnForceClose as ProtoOnForceClose,
|
|
WebSharing as ProtoWebSharing,
|
|
};
|
|
|
|
Self {
|
|
simplified_ui: options.simplified_ui,
|
|
theme: options.theme,
|
|
theme_dark: options.theme_dark,
|
|
theme_light: options.theme_light,
|
|
default_mode: options.default_mode.map(|m| input_mode_to_proto_i32(m)),
|
|
default_shell: options
|
|
.default_shell
|
|
.map(|p| p.to_string_lossy().to_string()),
|
|
default_cwd: options.default_cwd.map(|p| p.to_string_lossy().to_string()),
|
|
default_layout: options
|
|
.default_layout
|
|
.map(|p| p.to_string_lossy().to_string()),
|
|
layout_dir: options.layout_dir.map(|p| p.to_string_lossy().to_string()),
|
|
theme_dir: options.theme_dir.map(|p| p.to_string_lossy().to_string()),
|
|
keybinds_dir: options
|
|
.keybinds_dir
|
|
.map(|p| p.to_string_lossy().to_string()),
|
|
keybinds_preset: options.keybinds_preset,
|
|
keybinds_primary: options.keybinds_primary,
|
|
keybinds_secondary: options.keybinds_secondary,
|
|
keybinds_unlock: options.keybinds_unlock,
|
|
mouse_mode: options.mouse_mode,
|
|
pane_frames: options.pane_frames,
|
|
mirror_session: options.mirror_session,
|
|
on_force_close: options.on_force_close.map(|o| match o {
|
|
crate::input::options::OnForceClose::Quit => ProtoOnForceClose::Quit as i32,
|
|
crate::input::options::OnForceClose::Detach => ProtoOnForceClose::Detach as i32,
|
|
}),
|
|
scroll_buffer_size: options.scroll_buffer_size.map(|s| s as u32),
|
|
copy_command: options.copy_command,
|
|
copy_clipboard: options.copy_clipboard.map(|c| match c {
|
|
crate::input::options::Clipboard::System => ProtoClipboard::System as i32,
|
|
crate::input::options::Clipboard::Primary => ProtoClipboard::Primary as i32,
|
|
}),
|
|
copy_on_select: options.copy_on_select,
|
|
osc8_hyperlinks: options.osc8_hyperlinks,
|
|
scrollback_editor: options
|
|
.scrollback_editor
|
|
.map(|p| p.to_string_lossy().to_string()),
|
|
session_name: options.session_name,
|
|
attach_to_session: options.attach_to_session,
|
|
auto_layout: options.auto_layout,
|
|
session_serialization: options.session_serialization,
|
|
serialize_pane_viewport: options.serialize_pane_viewport,
|
|
scrollback_lines_to_serialize: options.scrollback_lines_to_serialize.map(|s| s as u32),
|
|
styled_underlines: options.styled_underlines,
|
|
serialization_interval: options.serialization_interval,
|
|
disable_session_metadata: options.disable_session_metadata,
|
|
support_kitty_keyboard_protocol: options.support_kitty_keyboard_protocol,
|
|
support_kitty_graphics_protocol: options.support_kitty_graphics_protocol,
|
|
web_server: options.web_server,
|
|
web_sharing: options.web_sharing.map(|w| match w {
|
|
crate::data::WebSharing::On => ProtoWebSharing::On as i32,
|
|
crate::data::WebSharing::Off => ProtoWebSharing::Off as i32,
|
|
crate::data::WebSharing::Disabled => ProtoWebSharing::Disabled as i32,
|
|
}),
|
|
stacked_resize: options.stacked_resize,
|
|
stacked_pane_list: options.stacked_pane_list,
|
|
dangerously_enable_paste_buffer_read: options.dangerously_enable_paste_buffer_read,
|
|
show_startup_tips: options.show_startup_tips,
|
|
show_release_notes: options.show_release_notes,
|
|
advanced_mouse_actions: options.advanced_mouse_actions,
|
|
mouse_scroll_resize: options.mouse_scroll_resize,
|
|
scroll_mode_sync: options.scroll_mode_sync,
|
|
mouse_hover_effects: options.mouse_hover_effects,
|
|
mouse_hover_tips: options.mouse_hover_tips,
|
|
web_server_ip: options.web_server_ip.map(|ip| ip.to_string()),
|
|
web_server_port: options.web_server_port.map(|p| p as u32),
|
|
web_server_cert: options
|
|
.web_server_cert
|
|
.map(|p| p.to_string_lossy().to_string()),
|
|
web_server_key: options
|
|
.web_server_key
|
|
.map(|p| p.to_string_lossy().to_string()),
|
|
enforce_https_for_localhost: options.enforce_https_for_localhost,
|
|
dangerously_allow_web_serving_without_a_certificate: options
|
|
.dangerously_allow_web_serving_without_a_certificate,
|
|
post_command_discovery_hook: options.post_command_discovery_hook,
|
|
client_async_worker_tasks: options.client_async_worker_tasks.map(|v| v as u64),
|
|
visual_bell: options.visual_bell,
|
|
focus_follows_mouse: options.focus_follows_mouse,
|
|
mouse_click_through: options.mouse_click_through,
|
|
context_menu_enabled: options.context_menu_enabled,
|
|
osc133_command_selection: options.osc133_command_selection,
|
|
word_separators: options.word_separators,
|
|
host_notification_protocol: options
|
|
.host_notification_protocol
|
|
.map(|p| p.as_str().to_owned()),
|
|
pane_frame_style: options.pane_frame_style.map(|s| match s {
|
|
crate::input::options::PaneFrameStyle::Full => "full".to_owned(),
|
|
crate::input::options::PaneFrameStyle::Titles => "titles".to_owned(),
|
|
crate::input::options::PaneFrameStyle::None => "none".to_owned(),
|
|
}),
|
|
nested_session_handling: options.nested_session_handling.map(|n| {
|
|
use crate::client_server_contract::client_server_contract::NestedSessionHandling as ProtoNestedSessionHandling;
|
|
use crate::input::options::NestedSessionHandling;
|
|
match n {
|
|
NestedSessionHandling::Ask => ProtoNestedSessionHandling::Ask as i32,
|
|
NestedSessionHandling::Fullscreen => {
|
|
ProtoNestedSessionHandling::Fullscreen as i32
|
|
},
|
|
NestedSessionHandling::Descend => ProtoNestedSessionHandling::Descend as i32,
|
|
NestedSessionHandling::Never => ProtoNestedSessionHandling::Never as i32,
|
|
}
|
|
}),
|
|
explicit_theme_hue: options.explicit_theme_hue.map(|hue| {
|
|
use crate::client_server_contract::client_server_contract::ThemeHue as ProtoThemeHue;
|
|
match hue {
|
|
crate::data::ThemeHue::Dark => ProtoThemeHue::Dark as i32,
|
|
crate::data::ThemeHue::Light => ProtoThemeHue::Light as i32,
|
|
}
|
|
}),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::Options>
|
|
for crate::input::options::Options
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
options: crate::client_server_contract::client_server_contract::Options,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::{
|
|
Clipboard as ProtoClipboard, NestedSessionHandling as ProtoNestedSessionHandling,
|
|
OnForceClose as ProtoOnForceClose, WebSharing as ProtoWebSharing,
|
|
};
|
|
|
|
Ok(Self {
|
|
simplified_ui: options.simplified_ui,
|
|
theme: options.theme,
|
|
theme_dark: options.theme_dark,
|
|
theme_light: options.theme_light,
|
|
default_mode: options
|
|
.default_mode
|
|
.map(|m| proto_i32_to_input_mode(m))
|
|
.transpose()?,
|
|
default_shell: options.default_shell.map(std::path::PathBuf::from),
|
|
default_cwd: options.default_cwd.map(std::path::PathBuf::from),
|
|
default_layout: options.default_layout.map(std::path::PathBuf::from),
|
|
layout_dir: options.layout_dir.map(std::path::PathBuf::from),
|
|
theme_dir: options.theme_dir.map(std::path::PathBuf::from),
|
|
keybinds_dir: options.keybinds_dir.map(std::path::PathBuf::from),
|
|
keybinds_preset: options.keybinds_preset,
|
|
keybinds_primary: options.keybinds_primary,
|
|
keybinds_secondary: options.keybinds_secondary,
|
|
keybinds_unlock: options.keybinds_unlock,
|
|
mouse_mode: options.mouse_mode,
|
|
pane_frames: options.pane_frames,
|
|
pane_frame_style: options.pane_frame_style.as_deref().and_then(|s| match s {
|
|
"full" => Some(crate::input::options::PaneFrameStyle::Full),
|
|
"titles" => Some(crate::input::options::PaneFrameStyle::Titles),
|
|
"none" => Some(crate::input::options::PaneFrameStyle::None),
|
|
_ => None,
|
|
}),
|
|
mirror_session: options.mirror_session,
|
|
on_force_close: options
|
|
.on_force_close
|
|
.map(|o| match ProtoOnForceClose::try_from(o).ok() {
|
|
Some(ProtoOnForceClose::Quit) => Ok(crate::input::options::OnForceClose::Quit),
|
|
Some(ProtoOnForceClose::Detach) => {
|
|
Ok(crate::input::options::OnForceClose::Detach)
|
|
},
|
|
_ => Err(anyhow!("Invalid OnForceClose value: {}", o)),
|
|
})
|
|
.transpose()?,
|
|
scroll_buffer_size: options.scroll_buffer_size.map(|s| s as usize),
|
|
copy_command: options.copy_command,
|
|
copy_clipboard: options
|
|
.copy_clipboard
|
|
.map(|c| match ProtoClipboard::try_from(c).ok() {
|
|
Some(ProtoClipboard::System) => Ok(crate::input::options::Clipboard::System),
|
|
Some(ProtoClipboard::Primary) => Ok(crate::input::options::Clipboard::Primary),
|
|
_ => Err(anyhow!("Invalid Clipboard value: {}", c)),
|
|
})
|
|
.transpose()?,
|
|
copy_on_select: options.copy_on_select,
|
|
osc8_hyperlinks: options.osc8_hyperlinks,
|
|
scrollback_editor: options.scrollback_editor.map(std::path::PathBuf::from),
|
|
session_name: options.session_name,
|
|
attach_to_session: options.attach_to_session,
|
|
auto_layout: options.auto_layout,
|
|
session_serialization: options.session_serialization,
|
|
serialize_pane_viewport: options.serialize_pane_viewport,
|
|
scrollback_lines_to_serialize: options
|
|
.scrollback_lines_to_serialize
|
|
.map(|s| s as usize),
|
|
styled_underlines: options.styled_underlines,
|
|
serialization_interval: options.serialization_interval,
|
|
disable_session_metadata: options.disable_session_metadata,
|
|
support_kitty_keyboard_protocol: options.support_kitty_keyboard_protocol,
|
|
support_kitty_graphics_protocol: options.support_kitty_graphics_protocol,
|
|
web_server: options.web_server,
|
|
web_sharing: options
|
|
.web_sharing
|
|
.map(|w| match ProtoWebSharing::try_from(w).ok() {
|
|
Some(ProtoWebSharing::On) => Ok(crate::data::WebSharing::On),
|
|
Some(ProtoWebSharing::Off) => Ok(crate::data::WebSharing::Off),
|
|
Some(ProtoWebSharing::Disabled) => Ok(crate::data::WebSharing::Disabled),
|
|
_ => Err(anyhow!("Invalid WebSharing value: {}", w)),
|
|
})
|
|
.transpose()?,
|
|
stacked_resize: options.stacked_resize,
|
|
stacked_pane_list: options.stacked_pane_list,
|
|
dangerously_enable_paste_buffer_read: options.dangerously_enable_paste_buffer_read,
|
|
show_startup_tips: options.show_startup_tips,
|
|
show_release_notes: options.show_release_notes,
|
|
advanced_mouse_actions: options.advanced_mouse_actions,
|
|
mouse_scroll_resize: options.mouse_scroll_resize,
|
|
scroll_mode_sync: options.scroll_mode_sync,
|
|
mouse_hover_effects: options.mouse_hover_effects,
|
|
mouse_hover_tips: options.mouse_hover_tips,
|
|
web_server_ip: options
|
|
.web_server_ip
|
|
.map(|ip| ip.parse())
|
|
.transpose()
|
|
.map_err(|e| anyhow!("Invalid IP address: {}", e))?,
|
|
web_server_port: options.web_server_port.map(|p| p as u16),
|
|
web_server_cert: options.web_server_cert.map(std::path::PathBuf::from),
|
|
web_server_key: options.web_server_key.map(std::path::PathBuf::from),
|
|
enforce_https_for_localhost: options.enforce_https_for_localhost,
|
|
dangerously_allow_web_serving_without_a_certificate: options
|
|
.dangerously_allow_web_serving_without_a_certificate,
|
|
post_command_discovery_hook: options.post_command_discovery_hook,
|
|
client_async_worker_tasks: options.client_async_worker_tasks.map(|v| v as usize),
|
|
visual_bell: options.visual_bell,
|
|
focus_follows_mouse: options.focus_follows_mouse,
|
|
mouse_click_through: options.mouse_click_through,
|
|
context_menu_enabled: options.context_menu_enabled,
|
|
osc133_command_selection: options.osc133_command_selection,
|
|
word_separators: options.word_separators,
|
|
host_notification_protocol: options
|
|
.host_notification_protocol
|
|
.map(|p| {
|
|
p.parse::<crate::input::options::HostNotificationProtocol>()
|
|
.map_err(|e| anyhow!(e))
|
|
})
|
|
.transpose()?,
|
|
nested_session_handling: options
|
|
.nested_session_handling
|
|
.map(|n| match ProtoNestedSessionHandling::try_from(n).ok() {
|
|
Some(ProtoNestedSessionHandling::Ask) => {
|
|
Ok(crate::input::options::NestedSessionHandling::Ask)
|
|
},
|
|
Some(ProtoNestedSessionHandling::Fullscreen) => {
|
|
Ok(crate::input::options::NestedSessionHandling::Fullscreen)
|
|
},
|
|
Some(ProtoNestedSessionHandling::Descend) => {
|
|
Ok(crate::input::options::NestedSessionHandling::Descend)
|
|
},
|
|
Some(ProtoNestedSessionHandling::Never) => {
|
|
Ok(crate::input::options::NestedSessionHandling::Never)
|
|
},
|
|
_ => Err(anyhow!("Invalid NestedSessionHandling value: {}", n)),
|
|
})
|
|
.transpose()?,
|
|
explicit_theme_hue: options
|
|
.explicit_theme_hue
|
|
.map(|hue| {
|
|
use crate::client_server_contract::client_server_contract::ThemeHue as ProtoThemeHue;
|
|
match ProtoThemeHue::try_from(hue).ok() {
|
|
Some(ProtoThemeHue::Dark) => Ok(crate::data::ThemeHue::Dark),
|
|
Some(ProtoThemeHue::Light) => Ok(crate::data::ThemeHue::Light),
|
|
_ => Err(anyhow!("Invalid ThemeHue value: {}", hue)),
|
|
}
|
|
})
|
|
.transpose()?,
|
|
})
|
|
}
|
|
}
|
|
|
|
// Complete Action conversion implementation - all 91 variants
|
|
impl From<crate::input::actions::Action>
|
|
for crate::client_server_contract::client_server_contract::Action
|
|
{
|
|
fn from(action: crate::input::actions::Action) -> Self {
|
|
use crate::client_server_contract::client_server_contract::{
|
|
action::ActionType,
|
|
ApplyFloatingSwapLayoutAction,
|
|
ApplyFloatingSwapLayoutByTabIdAction,
|
|
ApplyTiledSwapLayoutAction,
|
|
ApplyTiledSwapLayoutByTabIdAction,
|
|
AreFloatingPanesVisibleAction,
|
|
BreakPaneAction,
|
|
BreakPaneLeftAction,
|
|
BreakPaneRightAction,
|
|
ChangeFloatingPaneCoordinatesAction,
|
|
ClearScreenAction,
|
|
ClearScreenByPaneIdAction,
|
|
CliPipeAction,
|
|
CloseFocusAction,
|
|
CloseFocusByPaneIdAction,
|
|
ClosePluginPaneAction,
|
|
CloseTabAction,
|
|
CloseTabByIdAction,
|
|
CloseTerminalPaneAction,
|
|
ConfirmAction,
|
|
CopyAction,
|
|
CopyLastCommandOutputAction,
|
|
CurrentTabInfoAction,
|
|
DenyAction,
|
|
DetachAction,
|
|
DismissInfoPopupsAction,
|
|
DumpLayoutAction,
|
|
DumpScreenAction,
|
|
EditFileAction,
|
|
EditScrollbackAction,
|
|
EditScrollbackByPaneIdAction,
|
|
FocusGuestSessionAction,
|
|
FocusHostSessionAction,
|
|
FocusLastPaneAction,
|
|
FocusNextPaneAction,
|
|
FocusPaneByPaneIdAction,
|
|
FocusPluginPaneWithIdAction,
|
|
FocusPreviousPaneAction,
|
|
FocusTerminalPaneWithIdAction,
|
|
GoToNextTabAction,
|
|
GoToPreviousTabAction,
|
|
GoToTabAction,
|
|
GoToTabByIdAction,
|
|
GoToTabNameAction,
|
|
HalfPageScrollDownAction,
|
|
HalfPageScrollDownByPaneIdAction,
|
|
HalfPageScrollUpAction,
|
|
HalfPageScrollUpByPaneIdAction,
|
|
HideFloatingPanesAction,
|
|
KeybindPipeAction,
|
|
LaunchOrFocusPluginAction,
|
|
LaunchPluginAction,
|
|
ListClientsAction,
|
|
ListPanesAction,
|
|
ListTabsAction,
|
|
MouseEventAction,
|
|
MoveFocusAction,
|
|
MoveFocusOrTabAction,
|
|
MovePaneAction,
|
|
MovePaneBackwardsAction,
|
|
MovePaneBackwardsByPaneIdAction,
|
|
MovePaneByPaneIdAction,
|
|
MoveTabAction,
|
|
MoveTabByTabIdAction,
|
|
NewBlockingPaneAction,
|
|
NewFloatingPaneAction,
|
|
NewFloatingPluginPaneAction,
|
|
NewInPlacePaneAction,
|
|
NewInPlacePluginPaneAction,
|
|
NewPaneAction,
|
|
NewStackedPaneAction,
|
|
NewTabAction,
|
|
NewTiledPaneAction,
|
|
NewTiledPluginPaneAction,
|
|
NextSwapLayoutAction,
|
|
NextSwapLayoutByTabIdAction,
|
|
NoOpAction,
|
|
OpenContextMenuAction,
|
|
OverrideLayoutAction,
|
|
PageScrollDownAction,
|
|
PageScrollDownByPaneIdAction,
|
|
PageScrollUpAction,
|
|
PageScrollUpByPaneIdAction,
|
|
PaneIdWithPlugin,
|
|
PaneNameInputAction,
|
|
PasteAction,
|
|
PreviousSwapLayoutAction,
|
|
PreviousSwapLayoutByTabIdAction,
|
|
QueryTabNamesAction,
|
|
QuitAction,
|
|
RenamePaneByPaneIdAction,
|
|
RenamePluginPaneAction,
|
|
RenameSessionAction,
|
|
RenameTabAction,
|
|
RenameTabByIdAction,
|
|
RenameTerminalPaneAction,
|
|
ResizeAction,
|
|
ResizeByPaneIdAction,
|
|
RunAction,
|
|
SaveSessionAction,
|
|
ScrollDownAction,
|
|
ScrollDownAtAction,
|
|
ScrollDownByPaneIdAction,
|
|
ScrollToBottomAction,
|
|
ScrollToBottomByPaneIdAction,
|
|
ScrollToNextPromptAction,
|
|
ScrollToPreviousPromptAction,
|
|
ScrollToTopAction,
|
|
ScrollToTopByPaneIdAction,
|
|
ScrollUpAction,
|
|
ScrollUpAtAction,
|
|
// Pane-targeting
|
|
ScrollUpByPaneIdAction,
|
|
SearchAction,
|
|
SearchInputAction,
|
|
SearchToggleOptionAction,
|
|
SelectCommandAtScrollPositionAction,
|
|
SetDarkThemeAction,
|
|
SetLightThemeAction,
|
|
SetPaneBorderStyleAction,
|
|
SetPaneBorderlessAction,
|
|
SetPaneColorAction,
|
|
SetPaneFrameStyleAction,
|
|
ShowFloatingPanesAction,
|
|
SkipConfirmAction,
|
|
StackPanesAction,
|
|
StartOrReloadPluginAction,
|
|
StartRenamePaneByPaneIdAction,
|
|
StartRenameTabByTabIdAction,
|
|
SwitchFocusAction,
|
|
SwitchModeForAllClientsAction,
|
|
SwitchSessionAction,
|
|
SwitchToModeAction,
|
|
TabNameInputAction,
|
|
ToggleActiveSyncTabAction,
|
|
ToggleActiveSyncTabByTabIdAction,
|
|
ToggleFloatingPanesAction,
|
|
ToggleFloatingPanesByTabIdAction,
|
|
ToggleFocusFullscreenAction,
|
|
ToggleFocusNoUiFullscreenAction,
|
|
ToggleFullscreenByPaneIdAction,
|
|
ToggleGroupMarkingAction,
|
|
ToggleHostFullscreenAction,
|
|
ToggleMouseModeAction,
|
|
ToggleNoUiFullscreenByPaneIdAction,
|
|
TogglePaneBorderlessAction,
|
|
TogglePaneEmbedOrFloatingAction,
|
|
TogglePaneEmbedOrFloatingByPaneIdAction,
|
|
TogglePaneFramesAction,
|
|
TogglePaneInGroupAction,
|
|
TogglePaneInGroupByPaneIdAction,
|
|
TogglePanePinnedAction,
|
|
TogglePanePinnedByPaneIdAction,
|
|
ToggleTabAction,
|
|
ToggleThemeAction,
|
|
UndoRenamePaneAction,
|
|
UndoRenamePaneByPaneIdAction,
|
|
UndoRenameTabAction,
|
|
// Tab-targeting
|
|
UndoRenameTabByTabIdAction,
|
|
WriteAction,
|
|
WriteCharsAction,
|
|
WriteCharsToPaneIdAction,
|
|
WriteToPaneIdAction,
|
|
};
|
|
use std::collections::HashMap;
|
|
|
|
let action_type = match action {
|
|
crate::input::actions::Action::Quit => ActionType::Quit(QuitAction {}),
|
|
crate::input::actions::Action::Write {
|
|
key_with_modifier,
|
|
bytes,
|
|
is_kitty_keyboard_protocol,
|
|
} => ActionType::Write(WriteAction {
|
|
key_with_modifier: key_with_modifier.map(|k| k.into()),
|
|
bytes: bytes.into_iter().map(|b| b as u32).collect(),
|
|
is_kitty_keyboard_protocol,
|
|
}),
|
|
crate::input::actions::Action::WriteChars { chars } => {
|
|
ActionType::WriteChars(WriteCharsAction { chars })
|
|
},
|
|
crate::input::actions::Action::WriteToPaneId { bytes, pane_id } => {
|
|
ActionType::WriteToPaneId(WriteToPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
bytes: bytes.into_iter().map(|b| b as u32).collect(),
|
|
})
|
|
},
|
|
crate::input::actions::Action::WriteCharsToPaneId { chars, pane_id } => {
|
|
ActionType::WriteCharsToPaneId(WriteCharsToPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
chars,
|
|
})
|
|
},
|
|
crate::input::actions::Action::Paste { chars, pane_id } => {
|
|
ActionType::Paste(PasteAction {
|
|
chars,
|
|
pane_id: pane_id.map(|p| p.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::SwitchToMode { input_mode } => {
|
|
ActionType::SwitchToMode(SwitchToModeAction {
|
|
input_mode: input_mode_to_proto_i32(input_mode),
|
|
})
|
|
},
|
|
crate::input::actions::Action::SwitchModeForAllClients { input_mode } => {
|
|
ActionType::SwitchModeForAllClients(SwitchModeForAllClientsAction {
|
|
input_mode: input_mode_to_proto_i32(input_mode),
|
|
})
|
|
},
|
|
crate::input::actions::Action::Resize { resize, direction } => {
|
|
ActionType::Resize(ResizeAction {
|
|
resize: resize_to_proto_i32(resize),
|
|
direction: direction.map(|d| direction_to_proto_i32(d)),
|
|
})
|
|
},
|
|
crate::input::actions::Action::FocusNextPane => {
|
|
ActionType::FocusNextPane(FocusNextPaneAction {})
|
|
},
|
|
crate::input::actions::Action::FocusPreviousPane => {
|
|
ActionType::FocusPreviousPane(FocusPreviousPaneAction {})
|
|
},
|
|
crate::input::actions::Action::FocusLastPane => {
|
|
ActionType::FocusLastPane(FocusLastPaneAction {})
|
|
},
|
|
crate::input::actions::Action::FocusHostSession => {
|
|
ActionType::FocusHostSession(FocusHostSessionAction {})
|
|
},
|
|
crate::input::actions::Action::FocusGuestSession => {
|
|
ActionType::FocusGuestSession(FocusGuestSessionAction {})
|
|
},
|
|
crate::input::actions::Action::ToggleHostFullscreen => {
|
|
ActionType::ToggleHostFullscreen(ToggleHostFullscreenAction {})
|
|
},
|
|
crate::input::actions::Action::SwitchFocus => {
|
|
ActionType::SwitchFocus(SwitchFocusAction {})
|
|
},
|
|
crate::input::actions::Action::MoveFocus { direction } => {
|
|
ActionType::MoveFocus(MoveFocusAction {
|
|
direction: direction_to_proto_i32(direction),
|
|
})
|
|
},
|
|
crate::input::actions::Action::MoveFocusOrTab { direction } => {
|
|
ActionType::MoveFocusOrTab(MoveFocusOrTabAction {
|
|
direction: direction_to_proto_i32(direction),
|
|
})
|
|
},
|
|
crate::input::actions::Action::MovePane { direction } => {
|
|
ActionType::MovePane(MovePaneAction {
|
|
direction: direction.map(|d| direction_to_proto_i32(d)),
|
|
})
|
|
},
|
|
crate::input::actions::Action::MovePaneBackwards => {
|
|
ActionType::MovePaneBackwards(MovePaneBackwardsAction {})
|
|
},
|
|
crate::input::actions::Action::ClearScreen => {
|
|
ActionType::ClearScreen(ClearScreenAction {})
|
|
},
|
|
crate::input::actions::Action::DumpScreen {
|
|
file_path,
|
|
include_scrollback,
|
|
pane_id,
|
|
ansi,
|
|
} => {
|
|
let dump_to_stdout = file_path.is_none();
|
|
ActionType::DumpScreen(DumpScreenAction {
|
|
file_path: file_path.unwrap_or_default(),
|
|
include_scrollback,
|
|
pane_id: pane_id.map(|p| p.into()),
|
|
dump_to_stdout,
|
|
ansi,
|
|
})
|
|
},
|
|
crate::input::actions::Action::DumpLayout => {
|
|
ActionType::DumpLayout(DumpLayoutAction {})
|
|
},
|
|
crate::input::actions::Action::EditScrollback { ansi } => {
|
|
ActionType::EditScrollback(EditScrollbackAction { ansi })
|
|
},
|
|
crate::input::actions::Action::ScrollUp => ActionType::ScrollUp(ScrollUpAction {}),
|
|
crate::input::actions::Action::ScrollUpAt { position } => {
|
|
ActionType::ScrollUpAt(ScrollUpAtAction {
|
|
position: Some(position.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::ScrollDown => {
|
|
ActionType::ScrollDown(ScrollDownAction {})
|
|
},
|
|
crate::input::actions::Action::ScrollDownAt { position } => {
|
|
ActionType::ScrollDownAt(ScrollDownAtAction {
|
|
position: Some(position.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::ScrollToBottom => {
|
|
ActionType::ScrollToBottom(ScrollToBottomAction {})
|
|
},
|
|
crate::input::actions::Action::ScrollToTop => {
|
|
ActionType::ScrollToTop(ScrollToTopAction {})
|
|
},
|
|
crate::input::actions::Action::ScrollToPreviousPrompt => {
|
|
ActionType::ScrollToPreviousPrompt(ScrollToPreviousPromptAction {})
|
|
},
|
|
crate::input::actions::Action::ScrollToNextPrompt => {
|
|
ActionType::ScrollToNextPrompt(ScrollToNextPromptAction {})
|
|
},
|
|
crate::input::actions::Action::SelectCommandAtScrollPosition => {
|
|
ActionType::SelectCommandAtScrollPosition(SelectCommandAtScrollPositionAction {})
|
|
},
|
|
crate::input::actions::Action::CopyLastCommandOutput => {
|
|
ActionType::CopyLastCommandOutput(CopyLastCommandOutputAction {})
|
|
},
|
|
crate::input::actions::Action::PageScrollUp => {
|
|
ActionType::PageScrollUp(PageScrollUpAction {})
|
|
},
|
|
crate::input::actions::Action::PageScrollDown => {
|
|
ActionType::PageScrollDown(PageScrollDownAction {})
|
|
},
|
|
crate::input::actions::Action::HalfPageScrollUp => {
|
|
ActionType::HalfPageScrollUp(HalfPageScrollUpAction {})
|
|
},
|
|
crate::input::actions::Action::HalfPageScrollDown => {
|
|
ActionType::HalfPageScrollDown(HalfPageScrollDownAction {})
|
|
},
|
|
crate::input::actions::Action::ToggleFocusFullscreen => {
|
|
ActionType::ToggleFocusFullscreen(ToggleFocusFullscreenAction {})
|
|
},
|
|
crate::input::actions::Action::ToggleFocusNoUiFullscreen => {
|
|
ActionType::ToggleFocusNoUiFullscreen(ToggleFocusNoUiFullscreenAction {})
|
|
},
|
|
crate::input::actions::Action::TogglePaneFrames => {
|
|
ActionType::TogglePaneFrames(TogglePaneFramesAction {})
|
|
},
|
|
crate::input::actions::Action::SetPaneFrameStyle(style) => {
|
|
let style = match style {
|
|
crate::input::options::PaneFrameStyle::Full => "full",
|
|
crate::input::options::PaneFrameStyle::Titles => "titles",
|
|
crate::input::options::PaneFrameStyle::None => "none",
|
|
};
|
|
ActionType::SetPaneFrameStyle(SetPaneFrameStyleAction {
|
|
style: style.to_owned(),
|
|
})
|
|
},
|
|
crate::input::actions::Action::ToggleActiveSyncTab => {
|
|
ActionType::ToggleActiveSyncTab(ToggleActiveSyncTabAction {})
|
|
},
|
|
crate::input::actions::Action::NewPane {
|
|
direction,
|
|
pane_name,
|
|
start_suppressed,
|
|
} => ActionType::NewPane(NewPaneAction {
|
|
direction: direction.map(|d| direction_to_proto_i32(d)),
|
|
pane_name,
|
|
start_suppressed,
|
|
near_current_pane: false,
|
|
}),
|
|
crate::input::actions::Action::EditFile {
|
|
payload,
|
|
direction,
|
|
floating,
|
|
in_place,
|
|
close_replaced_pane,
|
|
start_suppressed,
|
|
coordinates,
|
|
near_current_pane,
|
|
no_focus,
|
|
tab_id,
|
|
..
|
|
} => ActionType::EditFile(EditFileAction {
|
|
payload: Some(payload.into()),
|
|
direction: direction.map(|d| direction_to_proto_i32(d)),
|
|
floating,
|
|
in_place,
|
|
close_replaced_pane,
|
|
start_suppressed,
|
|
coordinates: coordinates.map(|c| c.into()),
|
|
near_current_pane,
|
|
tab_id: tab_id.map(|t| t as u32),
|
|
no_focus,
|
|
}),
|
|
crate::input::actions::Action::NewFloatingPane {
|
|
command,
|
|
pane_name,
|
|
coordinates,
|
|
near_current_pane,
|
|
no_focus,
|
|
tab_id,
|
|
..
|
|
} => ActionType::NewFloatingPane(NewFloatingPaneAction {
|
|
command: command.map(|c| c.into()),
|
|
pane_name,
|
|
coordinates: coordinates.map(|c| c.into()),
|
|
near_current_pane,
|
|
tab_id: tab_id.map(|t| t as u32),
|
|
no_focus,
|
|
}),
|
|
crate::input::actions::Action::NewTiledPane {
|
|
direction,
|
|
command,
|
|
pane_name,
|
|
near_current_pane,
|
|
no_focus,
|
|
borderless,
|
|
border_style,
|
|
tab_id,
|
|
..
|
|
} => ActionType::NewTiledPane(NewTiledPaneAction {
|
|
direction: direction.map(|d| direction_to_proto_i32(d)),
|
|
command: command.map(|c| c.into()),
|
|
pane_name,
|
|
near_current_pane,
|
|
borderless,
|
|
border_style: border_style.map(|b| b.into()),
|
|
tab_id: tab_id.map(|t| t as u32),
|
|
no_focus,
|
|
}),
|
|
crate::input::actions::Action::NewInPlacePane {
|
|
command,
|
|
pane_name,
|
|
near_current_pane,
|
|
no_focus,
|
|
pane_id_to_replace,
|
|
close_replaced_pane,
|
|
tab_id,
|
|
..
|
|
} => ActionType::NewInPlacePane(NewInPlacePaneAction {
|
|
command: command.map(|c| c.into()),
|
|
pane_name,
|
|
near_current_pane,
|
|
pane_id_to_replace: pane_id_to_replace.and_then(|p| p.try_into().ok()),
|
|
close_replaced_pane,
|
|
tab_id: tab_id.map(|t| t as u32),
|
|
no_focus,
|
|
}),
|
|
crate::input::actions::Action::NewStackedPane {
|
|
command,
|
|
pane_name,
|
|
near_current_pane,
|
|
no_focus,
|
|
tab_id,
|
|
..
|
|
} => ActionType::NewStackedPane(NewStackedPaneAction {
|
|
command: command.map(|c| c.into()),
|
|
pane_name,
|
|
near_current_pane,
|
|
tab_id: tab_id.map(|t| t as u32),
|
|
no_focus,
|
|
}),
|
|
crate::input::actions::Action::NewBlockingPane {
|
|
placement,
|
|
pane_name,
|
|
command,
|
|
unblock_condition,
|
|
near_current_pane,
|
|
no_focus,
|
|
tab_id,
|
|
..
|
|
} => ActionType::NewBlockingPane(NewBlockingPaneAction {
|
|
placement: Some(placement.into()),
|
|
pane_name,
|
|
command: command.map(|c| c.into()),
|
|
unblock_condition: unblock_condition.map(|c| unblock_condition_to_proto_i32(c)),
|
|
near_current_pane,
|
|
tab_id: tab_id.map(|t| t as u32),
|
|
no_focus,
|
|
}),
|
|
crate::input::actions::Action::TogglePaneEmbedOrFloating => {
|
|
ActionType::TogglePaneEmbedOrFloating(TogglePaneEmbedOrFloatingAction {})
|
|
},
|
|
crate::input::actions::Action::ToggleFloatingPanes => {
|
|
ActionType::ToggleFloatingPanes(ToggleFloatingPanesAction {})
|
|
},
|
|
crate::input::actions::Action::ShowFloatingPanes { tab_id } => {
|
|
ActionType::ShowFloatingPanes(ShowFloatingPanesAction {
|
|
tab_id: tab_id.map(|id| id as u32),
|
|
})
|
|
},
|
|
crate::input::actions::Action::HideFloatingPanes { tab_id } => {
|
|
ActionType::HideFloatingPanes(HideFloatingPanesAction {
|
|
tab_id: tab_id.map(|id| id as u32),
|
|
})
|
|
},
|
|
crate::input::actions::Action::AreFloatingPanesVisible { tab_id } => {
|
|
ActionType::AreFloatingPanesVisible(AreFloatingPanesVisibleAction {
|
|
tab_id: tab_id.map(|id| id as u32),
|
|
})
|
|
},
|
|
crate::input::actions::Action::CloseFocus => {
|
|
ActionType::CloseFocus(CloseFocusAction {})
|
|
},
|
|
crate::input::actions::Action::PaneNameInput { input } => {
|
|
ActionType::PaneNameInput(PaneNameInputAction {
|
|
input: input.into_iter().map(|b| b as u32).collect(),
|
|
})
|
|
},
|
|
crate::input::actions::Action::UndoRenamePane => {
|
|
ActionType::UndoRenamePane(UndoRenamePaneAction {})
|
|
},
|
|
crate::input::actions::Action::NewTab {
|
|
tiled_layout,
|
|
floating_layouts,
|
|
swap_tiled_layouts,
|
|
swap_floating_layouts,
|
|
tab_name,
|
|
should_change_focus_to_new_tab,
|
|
cwd,
|
|
initial_panes,
|
|
first_pane_unblock_condition,
|
|
} => ActionType::NewTab(NewTabAction {
|
|
tiled_layout: tiled_layout.map(|l| l.into()),
|
|
floating_layouts: floating_layouts.into_iter().map(|l| l.into()).collect(),
|
|
swap_tiled_layouts: swap_tiled_layouts
|
|
.map(|layouts| layouts.into_iter().map(|l| l.into()).collect())
|
|
.unwrap_or_default(),
|
|
swap_floating_layouts: swap_floating_layouts
|
|
.map(|layouts| layouts.into_iter().map(|l| l.into()).collect())
|
|
.unwrap_or_default(),
|
|
tab_name,
|
|
should_change_focus_to_new_tab,
|
|
cwd: cwd.map(|p| p.to_string_lossy().to_string()),
|
|
initial_panes: initial_panes
|
|
.map(|panes| panes.into_iter().map(|p| p.into()).collect())
|
|
.unwrap_or_default(),
|
|
first_pane_unblock_condition: first_pane_unblock_condition
|
|
.map(|c| unblock_condition_to_proto_i32(c)),
|
|
}),
|
|
crate::input::actions::Action::NoOp => ActionType::NoOp(NoOpAction {}),
|
|
crate::input::actions::Action::GoToNextTab => {
|
|
ActionType::GoToNextTab(GoToNextTabAction {})
|
|
},
|
|
crate::input::actions::Action::GoToPreviousTab => {
|
|
ActionType::GoToPreviousTab(GoToPreviousTabAction {})
|
|
},
|
|
crate::input::actions::Action::CloseTab => ActionType::CloseTab(CloseTabAction {}),
|
|
crate::input::actions::Action::GoToTab { index } => {
|
|
ActionType::GoToTab(GoToTabAction { index })
|
|
},
|
|
crate::input::actions::Action::GoToTabName { name, create } => {
|
|
ActionType::GoToTabName(GoToTabNameAction { name, create })
|
|
},
|
|
crate::input::actions::Action::ToggleTab => ActionType::ToggleTab(ToggleTabAction {}),
|
|
crate::input::actions::Action::TabNameInput { input } => {
|
|
ActionType::TabNameInput(TabNameInputAction {
|
|
input: input.into_iter().map(|b| b as u32).collect(),
|
|
})
|
|
},
|
|
crate::input::actions::Action::UndoRenameTab => {
|
|
ActionType::UndoRenameTab(UndoRenameTabAction {})
|
|
},
|
|
crate::input::actions::Action::MoveTab { direction } => {
|
|
ActionType::MoveTab(MoveTabAction {
|
|
direction: direction_to_proto_i32(direction),
|
|
})
|
|
},
|
|
crate::input::actions::Action::Run {
|
|
command,
|
|
near_current_pane,
|
|
no_focus,
|
|
} => ActionType::Run(RunAction {
|
|
command: Some(command.into()),
|
|
near_current_pane,
|
|
no_focus,
|
|
}),
|
|
crate::input::actions::Action::Detach => ActionType::Detach(DetachAction {}),
|
|
crate::input::actions::Action::SetDarkTheme => {
|
|
ActionType::SetDarkTheme(SetDarkThemeAction {})
|
|
},
|
|
crate::input::actions::Action::SetLightTheme => {
|
|
ActionType::SetLightTheme(SetLightThemeAction {})
|
|
},
|
|
crate::input::actions::Action::ToggleTheme => {
|
|
ActionType::ToggleTheme(ToggleThemeAction {})
|
|
},
|
|
crate::input::actions::Action::DismissInfoPopups => {
|
|
ActionType::DismissInfoPopups(DismissInfoPopupsAction {})
|
|
},
|
|
crate::input::actions::Action::OpenContextMenu => {
|
|
ActionType::OpenContextMenu(OpenContextMenuAction {})
|
|
},
|
|
crate::input::actions::Action::SwitchSession {
|
|
name,
|
|
tab_position,
|
|
pane_id,
|
|
layout,
|
|
cwd,
|
|
} => ActionType::SwitchSession(SwitchSessionAction {
|
|
name: name.clone(),
|
|
tab_position: tab_position.map(|p| p as u32),
|
|
pane_id: pane_id.map(|(id, is_plugin)| PaneIdWithPlugin {
|
|
pane_id: id,
|
|
is_plugin: is_plugin,
|
|
}),
|
|
layout: layout.as_ref().map(|l| l.clone().into()),
|
|
cwd: cwd.as_ref().map(|p| p.to_string_lossy().to_string()),
|
|
}),
|
|
crate::input::actions::Action::LaunchOrFocusPlugin {
|
|
plugin,
|
|
should_float,
|
|
move_to_focused_tab,
|
|
should_open_in_place,
|
|
close_replaced_pane,
|
|
skip_cache,
|
|
tab_id,
|
|
..
|
|
} => ActionType::LaunchOrFocusPlugin(LaunchOrFocusPluginAction {
|
|
plugin: Some(plugin.into()),
|
|
should_float,
|
|
move_to_focused_tab,
|
|
should_open_in_place,
|
|
close_replaced_pane,
|
|
skip_cache,
|
|
tab_id: tab_id.map(|t| t as u32),
|
|
}),
|
|
crate::input::actions::Action::LaunchPlugin {
|
|
plugin,
|
|
should_float,
|
|
should_open_in_place,
|
|
close_replaced_pane,
|
|
skip_cache,
|
|
cwd,
|
|
no_focus,
|
|
tab_id,
|
|
..
|
|
} => ActionType::LaunchPlugin(LaunchPluginAction {
|
|
plugin: Some(plugin.into()),
|
|
should_float,
|
|
should_open_in_place,
|
|
close_replaced_pane,
|
|
skip_cache,
|
|
cwd: cwd.map(|p| p.to_string_lossy().to_string()),
|
|
tab_id: tab_id.map(|t| t as u32),
|
|
no_focus,
|
|
}),
|
|
crate::input::actions::Action::MouseEvent { event } => {
|
|
ActionType::MouseEvent(MouseEventAction {
|
|
event: Some(event.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::Copy => ActionType::Copy(CopyAction {}),
|
|
crate::input::actions::Action::Confirm => ActionType::Confirm(ConfirmAction {}),
|
|
crate::input::actions::Action::Deny => ActionType::Deny(DenyAction {}),
|
|
crate::input::actions::Action::SkipConfirm { action } => {
|
|
ActionType::SkipConfirm(Box::new(SkipConfirmAction {
|
|
action: Some(Box::new((*action).into())),
|
|
}))
|
|
},
|
|
crate::input::actions::Action::SearchInput { input } => {
|
|
ActionType::SearchInput(SearchInputAction {
|
|
input: input.into_iter().map(|b| b as u32).collect(),
|
|
})
|
|
},
|
|
crate::input::actions::Action::Search { direction } => {
|
|
ActionType::Search(SearchAction {
|
|
direction: search_direction_to_proto_i32(direction),
|
|
})
|
|
},
|
|
crate::input::actions::Action::SearchToggleOption { option } => {
|
|
ActionType::SearchToggleOption(SearchToggleOptionAction {
|
|
option: search_option_to_proto_i32(option),
|
|
})
|
|
},
|
|
crate::input::actions::Action::ToggleMouseMode => {
|
|
ActionType::ToggleMouseMode(ToggleMouseModeAction {})
|
|
},
|
|
crate::input::actions::Action::PreviousSwapLayout => {
|
|
ActionType::PreviousSwapLayout(PreviousSwapLayoutAction {})
|
|
},
|
|
crate::input::actions::Action::NextSwapLayout => {
|
|
ActionType::NextSwapLayout(NextSwapLayoutAction {})
|
|
},
|
|
crate::input::actions::Action::ApplyTiledSwapLayout { name } => {
|
|
ActionType::ApplyTiledSwapLayout(ApplyTiledSwapLayoutAction { name })
|
|
},
|
|
crate::input::actions::Action::ApplyFloatingSwapLayout { name } => {
|
|
ActionType::ApplyFloatingSwapLayout(ApplyFloatingSwapLayoutAction { name })
|
|
},
|
|
crate::input::actions::Action::OverrideLayout {
|
|
tabs,
|
|
retain_existing_terminal_panes,
|
|
retain_existing_plugin_panes,
|
|
apply_only_to_active_tab,
|
|
} => ActionType::OverrideLayout(OverrideLayoutAction {
|
|
tabs: tabs.into_iter().map(|t| t.into()).collect(),
|
|
retain_existing_terminal_panes,
|
|
retain_existing_plugin_panes,
|
|
apply_only_to_active_tab,
|
|
}),
|
|
crate::input::actions::Action::QueryTabNames => {
|
|
ActionType::QueryTabNames(QueryTabNamesAction {})
|
|
},
|
|
crate::input::actions::Action::NewTiledPluginPane {
|
|
plugin,
|
|
pane_name,
|
|
skip_cache,
|
|
cwd,
|
|
no_focus,
|
|
tab_id,
|
|
..
|
|
} => ActionType::NewTiledPluginPane(NewTiledPluginPaneAction {
|
|
plugin: Some(plugin.into()),
|
|
pane_name,
|
|
skip_cache,
|
|
cwd: cwd.map(|p| p.to_string_lossy().to_string()),
|
|
tab_id: tab_id.map(|t| t as u32),
|
|
no_focus,
|
|
}),
|
|
crate::input::actions::Action::NewFloatingPluginPane {
|
|
plugin,
|
|
pane_name,
|
|
skip_cache,
|
|
cwd,
|
|
coordinates,
|
|
no_focus,
|
|
tab_id,
|
|
..
|
|
} => ActionType::NewFloatingPluginPane(NewFloatingPluginPaneAction {
|
|
plugin: Some(plugin.into()),
|
|
pane_name,
|
|
skip_cache,
|
|
cwd: cwd.map(|p| p.to_string_lossy().to_string()),
|
|
coordinates: coordinates.map(|c| c.into()),
|
|
tab_id: tab_id.map(|t| t as u32),
|
|
no_focus,
|
|
}),
|
|
crate::input::actions::Action::NewInPlacePluginPane {
|
|
plugin,
|
|
pane_name,
|
|
skip_cache,
|
|
close_replaced_pane,
|
|
no_focus,
|
|
tab_id,
|
|
..
|
|
} => ActionType::NewInPlacePluginPane(NewInPlacePluginPaneAction {
|
|
plugin: Some(plugin.into()),
|
|
pane_name,
|
|
skip_cache,
|
|
close_replaced_pane,
|
|
tab_id: tab_id.map(|t| t as u32),
|
|
no_focus,
|
|
}),
|
|
crate::input::actions::Action::StartOrReloadPlugin { plugin } => {
|
|
ActionType::StartOrReloadPlugin(StartOrReloadPluginAction {
|
|
plugin: Some(plugin.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::CloseTerminalPane { pane_id } => {
|
|
ActionType::CloseTerminalPane(CloseTerminalPaneAction { pane_id })
|
|
},
|
|
crate::input::actions::Action::ClosePluginPane { pane_id } => {
|
|
ActionType::ClosePluginPane(ClosePluginPaneAction { pane_id })
|
|
},
|
|
crate::input::actions::Action::FocusTerminalPaneWithId {
|
|
pane_id,
|
|
should_float_if_hidden,
|
|
should_be_in_place_if_hidden,
|
|
} => ActionType::FocusTerminalPaneWithId(FocusTerminalPaneWithIdAction {
|
|
pane_id,
|
|
should_float_if_hidden,
|
|
should_be_in_place_if_hidden,
|
|
}),
|
|
crate::input::actions::Action::FocusPluginPaneWithId {
|
|
pane_id,
|
|
should_float_if_hidden,
|
|
should_be_in_place_if_hidden,
|
|
} => ActionType::FocusPluginPaneWithId(FocusPluginPaneWithIdAction {
|
|
pane_id,
|
|
should_float_if_hidden,
|
|
should_be_in_place_if_hidden,
|
|
}),
|
|
crate::input::actions::Action::RenameTerminalPane { pane_id, name } => {
|
|
ActionType::RenameTerminalPane(RenameTerminalPaneAction {
|
|
pane_id,
|
|
name: name.into_iter().map(|b| b as u32).collect(),
|
|
})
|
|
},
|
|
crate::input::actions::Action::RenamePluginPane { pane_id, name } => {
|
|
ActionType::RenamePluginPane(RenamePluginPaneAction {
|
|
pane_id,
|
|
name: name.into_iter().map(|b| b as u32).collect(),
|
|
})
|
|
},
|
|
crate::input::actions::Action::RenameTab { tab_index, name } => {
|
|
ActionType::RenameTab(RenameTabAction {
|
|
tab_index,
|
|
name: name.into_iter().map(|b| b as u32).collect(),
|
|
})
|
|
},
|
|
crate::input::actions::Action::GoToTabById { id } => {
|
|
ActionType::GoToTabById(GoToTabByIdAction { id })
|
|
},
|
|
crate::input::actions::Action::CloseTabById { id } => {
|
|
ActionType::CloseTabById(CloseTabByIdAction { id })
|
|
},
|
|
crate::input::actions::Action::RenameTabById { id, name } => {
|
|
ActionType::RenameTabById(RenameTabByIdAction { id, name })
|
|
},
|
|
crate::input::actions::Action::BreakPane => ActionType::BreakPane(BreakPaneAction {}),
|
|
crate::input::actions::Action::BreakPaneRight => {
|
|
ActionType::BreakPaneRight(BreakPaneRightAction {})
|
|
},
|
|
crate::input::actions::Action::BreakPaneLeft => {
|
|
ActionType::BreakPaneLeft(BreakPaneLeftAction {})
|
|
},
|
|
crate::input::actions::Action::RenameSession { name } => {
|
|
ActionType::RenameSession(RenameSessionAction { name })
|
|
},
|
|
crate::input::actions::Action::CliPipe {
|
|
pipe_id,
|
|
name,
|
|
payload,
|
|
args,
|
|
plugin,
|
|
configuration,
|
|
launch_new,
|
|
skip_cache,
|
|
floating,
|
|
in_place,
|
|
cwd,
|
|
pane_title,
|
|
popup,
|
|
popup_no_focus,
|
|
} => ActionType::CliPipe(CliPipeAction {
|
|
pipe_id,
|
|
name,
|
|
payload,
|
|
args: args
|
|
.map(|a| a.into_iter().collect::<HashMap<_, _>>())
|
|
.unwrap_or_default(),
|
|
plugin,
|
|
configuration: configuration
|
|
.map(|c| c.into_iter().collect::<HashMap<_, _>>())
|
|
.unwrap_or_default(),
|
|
launch_new,
|
|
skip_cache,
|
|
floating,
|
|
in_place,
|
|
cwd: cwd.map(|p| p.to_string_lossy().to_string()),
|
|
pane_title,
|
|
popup: popup.map(|p| p.to_string()),
|
|
popup_no_focus,
|
|
}),
|
|
crate::input::actions::Action::KeybindPipe {
|
|
name,
|
|
payload,
|
|
args,
|
|
plugin,
|
|
plugin_id,
|
|
configuration,
|
|
launch_new,
|
|
skip_cache,
|
|
floating,
|
|
in_place,
|
|
cwd,
|
|
pane_title,
|
|
} => ActionType::KeybindPipe(KeybindPipeAction {
|
|
name,
|
|
payload,
|
|
args: args
|
|
.map(|a| a.into_iter().collect::<HashMap<_, _>>())
|
|
.unwrap_or_default(),
|
|
plugin,
|
|
plugin_id,
|
|
configuration: configuration
|
|
.map(|c| c.into_iter().collect::<HashMap<_, _>>())
|
|
.unwrap_or_default(),
|
|
launch_new,
|
|
skip_cache,
|
|
floating,
|
|
in_place,
|
|
cwd: cwd.map(|p| p.to_string_lossy().to_string()),
|
|
pane_title,
|
|
}),
|
|
crate::input::actions::Action::ListClients => {
|
|
ActionType::ListClients(ListClientsAction {})
|
|
},
|
|
crate::input::actions::Action::ListPanes {
|
|
show_tab,
|
|
show_command,
|
|
show_state,
|
|
show_geometry,
|
|
show_all,
|
|
output_json,
|
|
} => ActionType::ListPanes(ListPanesAction {
|
|
show_tab,
|
|
show_command,
|
|
show_state,
|
|
show_geometry,
|
|
show_all,
|
|
output_json,
|
|
}),
|
|
crate::input::actions::Action::TogglePanePinned => {
|
|
ActionType::TogglePanePinned(TogglePanePinnedAction {})
|
|
},
|
|
crate::input::actions::Action::StackPanes { pane_ids } => {
|
|
ActionType::StackPanes(StackPanesAction {
|
|
pane_ids: pane_ids.into_iter().map(|id| id.into()).collect(),
|
|
})
|
|
},
|
|
crate::input::actions::Action::ChangeFloatingPaneCoordinates {
|
|
pane_id,
|
|
coordinates,
|
|
} => ActionType::ChangeFloatingPaneCoordinates(ChangeFloatingPaneCoordinatesAction {
|
|
pane_id: Some(pane_id.into()),
|
|
coordinates: Some(coordinates.into()),
|
|
}),
|
|
crate::input::actions::Action::TogglePaneBorderless { pane_id } => {
|
|
ActionType::TogglePaneBorderless(TogglePaneBorderlessAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::SetPaneBorderless {
|
|
pane_id,
|
|
borderless,
|
|
} => ActionType::SetPaneBorderless(SetPaneBorderlessAction {
|
|
pane_id: Some(pane_id.into()),
|
|
borderless,
|
|
}),
|
|
crate::input::actions::Action::SetPaneBorderStyle {
|
|
pane_id,
|
|
border_style,
|
|
} => ActionType::SetPaneBorderStyle(SetPaneBorderStyleAction {
|
|
pane_id: Some(pane_id.into()),
|
|
border_style: Some(border_style.into()),
|
|
}),
|
|
crate::input::actions::Action::TogglePaneInGroup => {
|
|
ActionType::TogglePaneInGroup(TogglePaneInGroupAction {})
|
|
},
|
|
crate::input::actions::Action::ToggleGroupMarking => {
|
|
ActionType::ToggleGroupMarking(ToggleGroupMarkingAction {})
|
|
},
|
|
crate::input::actions::Action::SaveSession => {
|
|
ActionType::SaveSession(SaveSessionAction {})
|
|
},
|
|
crate::input::actions::Action::ListTabs {
|
|
show_state,
|
|
show_dimensions,
|
|
show_panes,
|
|
show_layout,
|
|
show_all,
|
|
output_json,
|
|
} => ActionType::ListTabs(ListTabsAction {
|
|
show_state,
|
|
show_dimensions,
|
|
show_panes,
|
|
show_layout,
|
|
show_all,
|
|
output_json,
|
|
}),
|
|
crate::input::actions::Action::CurrentTabInfo { output_json } => {
|
|
ActionType::CurrentTabInfo(CurrentTabInfoAction { output_json })
|
|
},
|
|
crate::input::actions::Action::SetPaneColor { pane_id, fg, bg } => {
|
|
ActionType::SetPaneColor(SetPaneColorAction {
|
|
pane_id: Some(pane_id.into()),
|
|
fg,
|
|
bg,
|
|
})
|
|
},
|
|
// Pane-targeting CLI-only variants
|
|
crate::input::actions::Action::ScrollUpByPaneId { pane_id } => {
|
|
ActionType::ScrollUpByPaneId(ScrollUpByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::ScrollDownByPaneId { pane_id } => {
|
|
ActionType::ScrollDownByPaneId(ScrollDownByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::ScrollToTopByPaneId { pane_id } => {
|
|
ActionType::ScrollToTopByPaneId(ScrollToTopByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::ScrollToBottomByPaneId { pane_id } => {
|
|
ActionType::ScrollToBottomByPaneId(ScrollToBottomByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::PageScrollUpByPaneId { pane_id } => {
|
|
ActionType::PageScrollUpByPaneId(PageScrollUpByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::PageScrollDownByPaneId { pane_id } => {
|
|
ActionType::PageScrollDownByPaneId(PageScrollDownByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::HalfPageScrollUpByPaneId { pane_id } => {
|
|
ActionType::HalfPageScrollUpByPaneId(HalfPageScrollUpByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::HalfPageScrollDownByPaneId { pane_id } => {
|
|
ActionType::HalfPageScrollDownByPaneId(HalfPageScrollDownByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::ResizeByPaneId {
|
|
pane_id,
|
|
resize,
|
|
direction,
|
|
} => ActionType::ResizeByPaneId(ResizeByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
resize_action: Some(ResizeAction {
|
|
resize: resize_to_proto_i32(resize),
|
|
direction: direction.map(|d| direction_to_proto_i32(d)),
|
|
}),
|
|
}),
|
|
crate::input::actions::Action::MovePaneByPaneId { pane_id, direction } => {
|
|
ActionType::MovePaneByPaneId(MovePaneByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
direction: direction.map(|d| direction_to_proto_i32(d)),
|
|
})
|
|
},
|
|
crate::input::actions::Action::MovePaneBackwardsByPaneId { pane_id } => {
|
|
ActionType::MovePaneBackwardsByPaneId(MovePaneBackwardsByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::ClearScreenByPaneId { pane_id } => {
|
|
ActionType::ClearScreenByPaneId(ClearScreenByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::EditScrollbackByPaneId { pane_id, ansi } => {
|
|
ActionType::EditScrollbackByPaneId(EditScrollbackByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
ansi,
|
|
})
|
|
},
|
|
crate::input::actions::Action::ToggleFocusFullscreenByPaneId { pane_id } => {
|
|
ActionType::ToggleFullscreenByPaneId(ToggleFullscreenByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::ToggleFocusNoUiFullscreenByPaneId { pane_id } => {
|
|
ActionType::ToggleNoUiFullscreenByPaneId(ToggleNoUiFullscreenByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::TogglePaneEmbedOrFloatingByPaneId { pane_id } => {
|
|
ActionType::TogglePaneEmbedOrFloatingByPaneId(
|
|
TogglePaneEmbedOrFloatingByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
},
|
|
)
|
|
},
|
|
crate::input::actions::Action::CloseFocusByPaneId { pane_id } => {
|
|
ActionType::CloseFocusByPaneId(CloseFocusByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::RenamePaneByPaneId { pane_id, name } => {
|
|
ActionType::RenamePaneByPaneId(RenamePaneByPaneIdAction {
|
|
pane_id: pane_id.map(|id| id.into()),
|
|
name,
|
|
})
|
|
},
|
|
crate::input::actions::Action::UndoRenamePaneByPaneId { pane_id } => {
|
|
ActionType::UndoRenamePaneByPaneId(UndoRenamePaneByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::TogglePanePinnedByPaneId { pane_id } => {
|
|
ActionType::TogglePanePinnedByPaneId(TogglePanePinnedByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::TogglePaneInGroupByPaneId { pane_id } => {
|
|
ActionType::TogglePaneInGroupByPaneId(TogglePaneInGroupByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::StartRenamePaneByPaneId { pane_id } => {
|
|
ActionType::StartRenamePaneByPaneId(StartRenamePaneByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
crate::input::actions::Action::StartRenameTabByTabId { id } => {
|
|
ActionType::StartRenameTabByTabId(StartRenameTabByTabIdAction { id })
|
|
},
|
|
crate::input::actions::Action::FocusPaneByPaneId { pane_id } => {
|
|
ActionType::FocusPaneByPaneId(FocusPaneByPaneIdAction {
|
|
pane_id: Some(pane_id.into()),
|
|
})
|
|
},
|
|
// Tab-targeting CLI-only variants
|
|
crate::input::actions::Action::UndoRenameTabByTabId { id } => {
|
|
ActionType::UndoRenameTabByTabId(UndoRenameTabByTabIdAction { id })
|
|
},
|
|
crate::input::actions::Action::ToggleActiveSyncTabByTabId { id } => {
|
|
ActionType::ToggleActiveSyncTabByTabId(ToggleActiveSyncTabByTabIdAction { id })
|
|
},
|
|
crate::input::actions::Action::ToggleFloatingPanesByTabId { id } => {
|
|
ActionType::ToggleFloatingPanesByTabId(ToggleFloatingPanesByTabIdAction { id })
|
|
},
|
|
crate::input::actions::Action::PreviousSwapLayoutByTabId { id } => {
|
|
ActionType::PreviousSwapLayoutByTabId(PreviousSwapLayoutByTabIdAction { id })
|
|
},
|
|
crate::input::actions::Action::NextSwapLayoutByTabId { id } => {
|
|
ActionType::NextSwapLayoutByTabId(NextSwapLayoutByTabIdAction { id })
|
|
},
|
|
crate::input::actions::Action::ApplyTiledSwapLayoutByTabId { id, name } => {
|
|
ActionType::ApplyTiledSwapLayoutByTabId(ApplyTiledSwapLayoutByTabIdAction {
|
|
id,
|
|
name,
|
|
})
|
|
},
|
|
crate::input::actions::Action::ApplyFloatingSwapLayoutByTabId { id, name } => {
|
|
ActionType::ApplyFloatingSwapLayoutByTabId(ApplyFloatingSwapLayoutByTabIdAction {
|
|
id,
|
|
name,
|
|
})
|
|
},
|
|
crate::input::actions::Action::MoveTabByTabId { id, direction } => {
|
|
ActionType::MoveTabByTabId(MoveTabByTabIdAction {
|
|
id,
|
|
direction: direction_to_proto_i32(direction),
|
|
})
|
|
},
|
|
};
|
|
|
|
Self {
|
|
action_type: Some(action_type),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::Action>
|
|
for crate::input::actions::Action
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
action: crate::client_server_contract::client_server_contract::Action,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::action::ActionType;
|
|
|
|
let action_type = action
|
|
.action_type
|
|
.ok_or_else(|| anyhow!("Action missing action_type"))?;
|
|
|
|
match action_type {
|
|
ActionType::Quit(_) => Ok(crate::input::actions::Action::Quit),
|
|
ActionType::Write(write_action) => Ok(crate::input::actions::Action::Write {
|
|
key_with_modifier: write_action
|
|
.key_with_modifier
|
|
.map(|k| k.try_into())
|
|
.transpose()?,
|
|
bytes: write_action.bytes.into_iter().map(|b| b as u8).collect(),
|
|
is_kitty_keyboard_protocol: write_action.is_kitty_keyboard_protocol,
|
|
}),
|
|
ActionType::WriteChars(write_chars_action) => {
|
|
Ok(crate::input::actions::Action::WriteChars {
|
|
chars: write_chars_action.chars,
|
|
})
|
|
},
|
|
ActionType::WriteToPaneId(write_to_pane_id_action) => {
|
|
Ok(crate::input::actions::Action::WriteToPaneId {
|
|
bytes: write_to_pane_id_action
|
|
.bytes
|
|
.into_iter()
|
|
.map(|b| b as u8)
|
|
.collect(),
|
|
pane_id: write_to_pane_id_action
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("WriteToPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::WriteCharsToPaneId(write_chars_to_pane_id_action) => {
|
|
Ok(crate::input::actions::Action::WriteCharsToPaneId {
|
|
chars: write_chars_to_pane_id_action.chars,
|
|
pane_id: write_chars_to_pane_id_action
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("WriteCharsToPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::Paste(paste_action) => Ok(crate::input::actions::Action::Paste {
|
|
chars: paste_action.chars,
|
|
pane_id: paste_action.pane_id.map(|p| p.try_into()).transpose()?,
|
|
}),
|
|
ActionType::SwitchToMode(switch_mode_action) => {
|
|
Ok(crate::input::actions::Action::SwitchToMode {
|
|
input_mode: proto_i32_to_input_mode(switch_mode_action.input_mode)?,
|
|
})
|
|
},
|
|
ActionType::SwitchModeForAllClients(switch_mode_action) => {
|
|
Ok(crate::input::actions::Action::SwitchModeForAllClients {
|
|
input_mode: proto_i32_to_input_mode(switch_mode_action.input_mode)?,
|
|
})
|
|
},
|
|
ActionType::Resize(resize_action) => Ok(crate::input::actions::Action::Resize {
|
|
resize: proto_i32_to_resize(resize_action.resize)?,
|
|
direction: resize_action
|
|
.direction
|
|
.map(|d| proto_i32_to_direction(d))
|
|
.transpose()?,
|
|
}),
|
|
ActionType::FocusNextPane(_) => Ok(crate::input::actions::Action::FocusNextPane),
|
|
ActionType::FocusPreviousPane(_) => {
|
|
Ok(crate::input::actions::Action::FocusPreviousPane)
|
|
},
|
|
ActionType::FocusLastPane(_) => Ok(crate::input::actions::Action::FocusLastPane),
|
|
ActionType::SwitchFocus(_) => Ok(crate::input::actions::Action::SwitchFocus),
|
|
ActionType::MoveFocus(move_focus_action) => {
|
|
Ok(crate::input::actions::Action::MoveFocus {
|
|
direction: proto_i32_to_direction(move_focus_action.direction)?,
|
|
})
|
|
},
|
|
ActionType::MoveFocusOrTab(move_focus_action) => {
|
|
Ok(crate::input::actions::Action::MoveFocusOrTab {
|
|
direction: proto_i32_to_direction(move_focus_action.direction)?,
|
|
})
|
|
},
|
|
ActionType::MovePane(move_pane_action) => Ok(crate::input::actions::Action::MovePane {
|
|
direction: move_pane_action
|
|
.direction
|
|
.map(|d| proto_i32_to_direction(d))
|
|
.transpose()?,
|
|
}),
|
|
ActionType::MovePaneBackwards(_) => {
|
|
Ok(crate::input::actions::Action::MovePaneBackwards)
|
|
},
|
|
ActionType::ClearScreen(_) => Ok(crate::input::actions::Action::ClearScreen),
|
|
ActionType::DumpScreen(dump_screen_action) => {
|
|
let file_path = if dump_screen_action.dump_to_stdout {
|
|
None
|
|
} else {
|
|
Some(dump_screen_action.file_path)
|
|
};
|
|
Ok(crate::input::actions::Action::DumpScreen {
|
|
file_path,
|
|
include_scrollback: dump_screen_action.include_scrollback,
|
|
pane_id: dump_screen_action.pane_id.and_then(|p| p.try_into().ok()),
|
|
ansi: dump_screen_action.ansi,
|
|
})
|
|
},
|
|
ActionType::DumpLayout(_) => Ok(crate::input::actions::Action::DumpLayout),
|
|
ActionType::SaveSession(_) => Ok(crate::input::actions::Action::SaveSession),
|
|
ActionType::EditScrollback(edit_scrollback_action) => {
|
|
Ok(crate::input::actions::Action::EditScrollback {
|
|
ansi: edit_scrollback_action.ansi,
|
|
})
|
|
},
|
|
ActionType::ScrollUp(_) => Ok(crate::input::actions::Action::ScrollUp),
|
|
ActionType::ScrollToPreviousPrompt(_) => {
|
|
Ok(crate::input::actions::Action::ScrollToPreviousPrompt)
|
|
},
|
|
ActionType::ScrollToNextPrompt(_) => {
|
|
Ok(crate::input::actions::Action::ScrollToNextPrompt)
|
|
},
|
|
ActionType::SelectCommandAtScrollPosition(_) => {
|
|
Ok(crate::input::actions::Action::SelectCommandAtScrollPosition)
|
|
},
|
|
ActionType::CopyLastCommandOutput(_) => {
|
|
Ok(crate::input::actions::Action::CopyLastCommandOutput)
|
|
},
|
|
ActionType::ScrollUpAt(scroll_action) => {
|
|
Ok(crate::input::actions::Action::ScrollUpAt {
|
|
position: scroll_action
|
|
.position
|
|
.ok_or_else(|| anyhow!("ScrollUpAt missing position"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::ScrollDown(_) => Ok(crate::input::actions::Action::ScrollDown),
|
|
ActionType::ScrollDownAt(scroll_action) => {
|
|
Ok(crate::input::actions::Action::ScrollDownAt {
|
|
position: scroll_action
|
|
.position
|
|
.ok_or_else(|| anyhow!("ScrollDownAt missing position"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::ScrollToBottom(_) => Ok(crate::input::actions::Action::ScrollToBottom),
|
|
ActionType::ScrollToTop(_) => Ok(crate::input::actions::Action::ScrollToTop),
|
|
ActionType::PageScrollUp(_) => Ok(crate::input::actions::Action::PageScrollUp),
|
|
ActionType::PageScrollDown(_) => Ok(crate::input::actions::Action::PageScrollDown),
|
|
ActionType::HalfPageScrollUp(_) => Ok(crate::input::actions::Action::HalfPageScrollUp),
|
|
ActionType::HalfPageScrollDown(_) => {
|
|
Ok(crate::input::actions::Action::HalfPageScrollDown)
|
|
},
|
|
ActionType::ToggleFocusFullscreen(_) => {
|
|
Ok(crate::input::actions::Action::ToggleFocusFullscreen)
|
|
},
|
|
ActionType::ToggleFocusNoUiFullscreen(_) => {
|
|
Ok(crate::input::actions::Action::ToggleFocusNoUiFullscreen)
|
|
},
|
|
ActionType::TogglePaneFrames(_) => Ok(crate::input::actions::Action::TogglePaneFrames),
|
|
ActionType::SetPaneFrameStyle(set_pane_frame_style_action) => {
|
|
let style = crate::input::options::PaneFrameStyle::from_str(
|
|
&set_pane_frame_style_action.style,
|
|
)
|
|
.map_err(|e| anyhow!("{}", e))?;
|
|
Ok(crate::input::actions::Action::SetPaneFrameStyle(style))
|
|
},
|
|
ActionType::ToggleActiveSyncTab(_) => {
|
|
Ok(crate::input::actions::Action::ToggleActiveSyncTab)
|
|
},
|
|
ActionType::NewPane(new_pane_action) => Ok(crate::input::actions::Action::NewPane {
|
|
direction: new_pane_action
|
|
.direction
|
|
.map(|d| proto_i32_to_direction(d))
|
|
.transpose()?,
|
|
pane_name: new_pane_action.pane_name,
|
|
start_suppressed: new_pane_action.start_suppressed,
|
|
}),
|
|
ActionType::EditFile(edit_file_action) => Ok(crate::input::actions::Action::EditFile {
|
|
payload: edit_file_action
|
|
.payload
|
|
.ok_or_else(|| anyhow!("EditFile missing payload"))?
|
|
.try_into()?,
|
|
direction: edit_file_action
|
|
.direction
|
|
.map(|d| proto_i32_to_direction(d))
|
|
.transpose()?,
|
|
floating: edit_file_action.floating,
|
|
in_place: edit_file_action.in_place,
|
|
close_replaced_pane: edit_file_action.close_replaced_pane,
|
|
start_suppressed: edit_file_action.start_suppressed,
|
|
coordinates: edit_file_action
|
|
.coordinates
|
|
.map(|c| c.try_into())
|
|
.transpose()?,
|
|
near_current_pane: edit_file_action.near_current_pane,
|
|
no_focus: edit_file_action.no_focus,
|
|
tab_id: edit_file_action.tab_id.map(|t| t as usize),
|
|
}),
|
|
ActionType::NewFloatingPane(new_floating_action) => {
|
|
Ok(crate::input::actions::Action::NewFloatingPane {
|
|
command: new_floating_action
|
|
.command
|
|
.map(|c| c.try_into())
|
|
.transpose()?,
|
|
pane_name: new_floating_action.pane_name,
|
|
coordinates: new_floating_action
|
|
.coordinates
|
|
.map(|c| c.try_into())
|
|
.transpose()?,
|
|
near_current_pane: new_floating_action.near_current_pane,
|
|
no_focus: new_floating_action.no_focus,
|
|
tab_id: new_floating_action.tab_id.map(|t| t as usize),
|
|
})
|
|
},
|
|
ActionType::NewTiledPane(new_tiled_action) => {
|
|
Ok(crate::input::actions::Action::NewTiledPane {
|
|
direction: new_tiled_action
|
|
.direction
|
|
.map(|d| proto_i32_to_direction(d))
|
|
.transpose()?,
|
|
command: new_tiled_action.command.map(|c| c.try_into()).transpose()?,
|
|
pane_name: new_tiled_action.pane_name,
|
|
near_current_pane: new_tiled_action.near_current_pane,
|
|
no_focus: new_tiled_action.no_focus,
|
|
borderless: new_tiled_action.borderless,
|
|
border_style: new_tiled_action.border_style.map(|b| b.into()),
|
|
tab_id: new_tiled_action.tab_id.map(|t| t as usize),
|
|
})
|
|
},
|
|
ActionType::NewInPlacePane(new_in_place_action) => {
|
|
Ok(crate::input::actions::Action::NewInPlacePane {
|
|
command: new_in_place_action
|
|
.command
|
|
.map(|c| c.try_into())
|
|
.transpose()?,
|
|
pane_name: new_in_place_action.pane_name,
|
|
near_current_pane: new_in_place_action.near_current_pane,
|
|
no_focus: new_in_place_action.no_focus,
|
|
pane_id_to_replace: new_in_place_action
|
|
.pane_id_to_replace
|
|
.and_then(|p| p.try_into().ok()),
|
|
close_replaced_pane: new_in_place_action.close_replaced_pane,
|
|
tab_id: new_in_place_action.tab_id.map(|t| t as usize),
|
|
})
|
|
},
|
|
ActionType::NewStackedPane(new_stacked_action) => {
|
|
Ok(crate::input::actions::Action::NewStackedPane {
|
|
command: new_stacked_action
|
|
.command
|
|
.map(|c| c.try_into())
|
|
.transpose()?,
|
|
pane_name: new_stacked_action.pane_name,
|
|
near_current_pane: new_stacked_action.near_current_pane,
|
|
no_focus: new_stacked_action.no_focus,
|
|
tab_id: new_stacked_action.tab_id.map(|t| t as usize),
|
|
})
|
|
},
|
|
ActionType::NewBlockingPane(new_blocking_action) => {
|
|
Ok(crate::input::actions::Action::NewBlockingPane {
|
|
placement: new_blocking_action
|
|
.placement
|
|
.ok_or_else(|| anyhow!("NewBlockingPane missing placement"))?
|
|
.try_into()?,
|
|
pane_name: new_blocking_action.pane_name,
|
|
command: new_blocking_action
|
|
.command
|
|
.map(|c| c.try_into())
|
|
.transpose()?,
|
|
unblock_condition: new_blocking_action
|
|
.unblock_condition
|
|
.map(|c| proto_i32_to_unblock_condition(c))
|
|
.transpose()?,
|
|
near_current_pane: new_blocking_action.near_current_pane,
|
|
no_focus: new_blocking_action.no_focus,
|
|
tab_id: new_blocking_action.tab_id.map(|t| t as usize),
|
|
})
|
|
},
|
|
ActionType::TogglePaneEmbedOrFloating(_) => {
|
|
Ok(crate::input::actions::Action::TogglePaneEmbedOrFloating)
|
|
},
|
|
ActionType::ToggleFloatingPanes(_) => {
|
|
Ok(crate::input::actions::Action::ToggleFloatingPanes)
|
|
},
|
|
ActionType::ShowFloatingPanes(a) => {
|
|
Ok(crate::input::actions::Action::ShowFloatingPanes {
|
|
tab_id: a.tab_id.map(|id| id as usize),
|
|
})
|
|
},
|
|
ActionType::HideFloatingPanes(a) => {
|
|
Ok(crate::input::actions::Action::HideFloatingPanes {
|
|
tab_id: a.tab_id.map(|id| id as usize),
|
|
})
|
|
},
|
|
ActionType::AreFloatingPanesVisible(a) => {
|
|
Ok(crate::input::actions::Action::AreFloatingPanesVisible {
|
|
tab_id: a.tab_id.map(|id| id as usize),
|
|
})
|
|
},
|
|
ActionType::CloseFocus(_) => Ok(crate::input::actions::Action::CloseFocus),
|
|
ActionType::PaneNameInput(pane_name_action) => {
|
|
Ok(crate::input::actions::Action::PaneNameInput {
|
|
input: pane_name_action
|
|
.input
|
|
.into_iter()
|
|
.map(|b| b as u8)
|
|
.collect(),
|
|
})
|
|
},
|
|
ActionType::UndoRenamePane(_) => Ok(crate::input::actions::Action::UndoRenamePane),
|
|
ActionType::NewTab(new_tab_action) => Ok(crate::input::actions::Action::NewTab {
|
|
tiled_layout: new_tab_action
|
|
.tiled_layout
|
|
.map(|l| l.try_into())
|
|
.transpose()?,
|
|
floating_layouts: new_tab_action
|
|
.floating_layouts
|
|
.into_iter()
|
|
.map(|l| l.try_into())
|
|
.collect::<Result<Vec<_>>>()?,
|
|
swap_tiled_layouts: if new_tab_action.swap_tiled_layouts.is_empty() {
|
|
None
|
|
} else {
|
|
Some(
|
|
new_tab_action
|
|
.swap_tiled_layouts
|
|
.into_iter()
|
|
.map(|l| l.try_into())
|
|
.collect::<Result<Vec<_>>>()?,
|
|
)
|
|
},
|
|
swap_floating_layouts: if new_tab_action.swap_floating_layouts.is_empty() {
|
|
None
|
|
} else {
|
|
Some(
|
|
new_tab_action
|
|
.swap_floating_layouts
|
|
.into_iter()
|
|
.map(|l| l.try_into())
|
|
.collect::<Result<Vec<_>>>()?,
|
|
)
|
|
},
|
|
tab_name: new_tab_action.tab_name,
|
|
should_change_focus_to_new_tab: new_tab_action.should_change_focus_to_new_tab,
|
|
cwd: new_tab_action.cwd.map(PathBuf::from),
|
|
initial_panes: if new_tab_action.initial_panes.is_empty() {
|
|
None
|
|
} else {
|
|
Some(
|
|
new_tab_action
|
|
.initial_panes
|
|
.into_iter()
|
|
.map(|p| p.try_into())
|
|
.collect::<Result<Vec<_>>>()?,
|
|
)
|
|
},
|
|
|
|
first_pane_unblock_condition: new_tab_action
|
|
.first_pane_unblock_condition
|
|
.map(|c| proto_i32_to_unblock_condition(c))
|
|
.transpose()?,
|
|
}),
|
|
ActionType::NoOp(_) => Ok(crate::input::actions::Action::NoOp),
|
|
ActionType::GoToNextTab(_) => Ok(crate::input::actions::Action::GoToNextTab),
|
|
ActionType::GoToPreviousTab(_) => Ok(crate::input::actions::Action::GoToPreviousTab),
|
|
ActionType::CloseTab(_) => Ok(crate::input::actions::Action::CloseTab),
|
|
ActionType::GoToTab(go_to_tab_action) => Ok(crate::input::actions::Action::GoToTab {
|
|
index: go_to_tab_action.index,
|
|
}),
|
|
ActionType::GoToTabName(go_to_tab_name_action) => {
|
|
Ok(crate::input::actions::Action::GoToTabName {
|
|
name: go_to_tab_name_action.name,
|
|
create: go_to_tab_name_action.create,
|
|
})
|
|
},
|
|
ActionType::ToggleTab(_) => Ok(crate::input::actions::Action::ToggleTab),
|
|
ActionType::TabNameInput(tab_name_action) => {
|
|
Ok(crate::input::actions::Action::TabNameInput {
|
|
input: tab_name_action.input.into_iter().map(|b| b as u8).collect(),
|
|
})
|
|
},
|
|
ActionType::UndoRenameTab(_) => Ok(crate::input::actions::Action::UndoRenameTab),
|
|
ActionType::MoveTab(move_tab_action) => Ok(crate::input::actions::Action::MoveTab {
|
|
direction: proto_i32_to_direction(move_tab_action.direction)?,
|
|
}),
|
|
ActionType::Run(run_action) => Ok(crate::input::actions::Action::Run {
|
|
command: run_action
|
|
.command
|
|
.ok_or_else(|| anyhow!("Run missing command"))?
|
|
.try_into()?,
|
|
near_current_pane: run_action.near_current_pane,
|
|
no_focus: run_action.no_focus,
|
|
}),
|
|
ActionType::Detach(_) => Ok(crate::input::actions::Action::Detach),
|
|
ActionType::SetDarkTheme(_) => Ok(crate::input::actions::Action::SetDarkTheme),
|
|
ActionType::SetLightTheme(_) => Ok(crate::input::actions::Action::SetLightTheme),
|
|
ActionType::ToggleTheme(_) => Ok(crate::input::actions::Action::ToggleTheme),
|
|
ActionType::DismissInfoPopups(_) => {
|
|
Ok(crate::input::actions::Action::DismissInfoPopups)
|
|
},
|
|
ActionType::OpenContextMenu(_) => Ok(crate::input::actions::Action::OpenContextMenu),
|
|
ActionType::SwitchSession(switch_session_action) => {
|
|
Ok(crate::input::actions::Action::SwitchSession {
|
|
name: switch_session_action.name.clone(),
|
|
tab_position: switch_session_action.tab_position.map(|p| p as usize),
|
|
pane_id: switch_session_action
|
|
.pane_id
|
|
.as_ref()
|
|
.map(|p| (p.pane_id, p.is_plugin)),
|
|
layout: switch_session_action
|
|
.layout
|
|
.map(|l| l.try_into())
|
|
.transpose()?,
|
|
cwd: switch_session_action.cwd.map(PathBuf::from),
|
|
})
|
|
},
|
|
ActionType::LaunchOrFocusPlugin(launch_plugin_action) => {
|
|
Ok(crate::input::actions::Action::LaunchOrFocusPlugin {
|
|
plugin: launch_plugin_action
|
|
.plugin
|
|
.ok_or_else(|| anyhow!("LaunchOrFocusPlugin missing plugin"))?
|
|
.try_into()?,
|
|
should_float: launch_plugin_action.should_float,
|
|
move_to_focused_tab: launch_plugin_action.move_to_focused_tab,
|
|
should_open_in_place: launch_plugin_action.should_open_in_place,
|
|
close_replaced_pane: launch_plugin_action.close_replaced_pane,
|
|
skip_cache: launch_plugin_action.skip_cache,
|
|
tab_id: launch_plugin_action.tab_id.map(|t| t as usize),
|
|
})
|
|
},
|
|
ActionType::LaunchPlugin(launch_plugin_action) => {
|
|
Ok(crate::input::actions::Action::LaunchPlugin {
|
|
plugin: launch_plugin_action
|
|
.plugin
|
|
.ok_or_else(|| anyhow!("LaunchPlugin missing plugin"))?
|
|
.try_into()?,
|
|
should_float: launch_plugin_action.should_float,
|
|
should_open_in_place: launch_plugin_action.should_open_in_place,
|
|
close_replaced_pane: launch_plugin_action.close_replaced_pane,
|
|
skip_cache: launch_plugin_action.skip_cache,
|
|
cwd: launch_plugin_action.cwd.map(PathBuf::from),
|
|
no_focus: launch_plugin_action.no_focus,
|
|
tab_id: launch_plugin_action.tab_id.map(|t| t as usize),
|
|
})
|
|
},
|
|
ActionType::MouseEvent(mouse_event_action) => {
|
|
Ok(crate::input::actions::Action::MouseEvent {
|
|
event: mouse_event_action
|
|
.event
|
|
.ok_or_else(|| anyhow!("MouseEvent missing event"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::Copy(_) => Ok(crate::input::actions::Action::Copy),
|
|
ActionType::Confirm(_) => Ok(crate::input::actions::Action::Confirm),
|
|
ActionType::Deny(_) => Ok(crate::input::actions::Action::Deny),
|
|
ActionType::SkipConfirm(skip_confirm_action) => {
|
|
Ok(crate::input::actions::Action::SkipConfirm {
|
|
action: Box::new(
|
|
skip_confirm_action
|
|
.action
|
|
.ok_or_else(|| anyhow!("SkipConfirm missing action"))?
|
|
.as_ref()
|
|
.clone()
|
|
.try_into()?,
|
|
),
|
|
})
|
|
},
|
|
ActionType::SearchInput(search_input_action) => {
|
|
Ok(crate::input::actions::Action::SearchInput {
|
|
input: search_input_action
|
|
.input
|
|
.into_iter()
|
|
.map(|b| b as u8)
|
|
.collect(),
|
|
})
|
|
},
|
|
ActionType::Search(search_action) => Ok(crate::input::actions::Action::Search {
|
|
direction: proto_i32_to_search_direction(search_action.direction)?,
|
|
}),
|
|
ActionType::SearchToggleOption(search_toggle_action) => {
|
|
Ok(crate::input::actions::Action::SearchToggleOption {
|
|
option: proto_i32_to_search_option(search_toggle_action.option)?,
|
|
})
|
|
},
|
|
ActionType::ToggleMouseMode(_) => Ok(crate::input::actions::Action::ToggleMouseMode),
|
|
ActionType::PreviousSwapLayout(_) => {
|
|
Ok(crate::input::actions::Action::PreviousSwapLayout)
|
|
},
|
|
ActionType::NextSwapLayout(_) => Ok(crate::input::actions::Action::NextSwapLayout),
|
|
ActionType::ApplyTiledSwapLayout(a) => {
|
|
Ok(crate::input::actions::Action::ApplyTiledSwapLayout { name: a.name })
|
|
},
|
|
ActionType::ApplyFloatingSwapLayout(a) => {
|
|
Ok(crate::input::actions::Action::ApplyFloatingSwapLayout { name: a.name })
|
|
},
|
|
ActionType::OverrideLayout(override_layout_action) => {
|
|
Ok(crate::input::actions::Action::OverrideLayout {
|
|
tabs: override_layout_action
|
|
.tabs
|
|
.into_iter()
|
|
.map(|t| t.try_into())
|
|
.collect::<Result<Vec<_>>>()?,
|
|
retain_existing_terminal_panes: override_layout_action
|
|
.retain_existing_terminal_panes,
|
|
retain_existing_plugin_panes: override_layout_action
|
|
.retain_existing_plugin_panes,
|
|
apply_only_to_active_tab: override_layout_action.apply_only_to_active_tab,
|
|
})
|
|
},
|
|
ActionType::QueryTabNames(_) => Ok(crate::input::actions::Action::QueryTabNames),
|
|
ActionType::NewTiledPluginPane(new_tiled_plugin_action) => {
|
|
Ok(crate::input::actions::Action::NewTiledPluginPane {
|
|
plugin: new_tiled_plugin_action
|
|
.plugin
|
|
.ok_or_else(|| anyhow!("NewTiledPluginPane missing plugin"))?
|
|
.try_into()?,
|
|
pane_name: new_tiled_plugin_action.pane_name,
|
|
skip_cache: new_tiled_plugin_action.skip_cache,
|
|
cwd: new_tiled_plugin_action.cwd.map(PathBuf::from),
|
|
no_focus: new_tiled_plugin_action.no_focus,
|
|
tab_id: new_tiled_plugin_action.tab_id.map(|t| t as usize),
|
|
})
|
|
},
|
|
ActionType::NewFloatingPluginPane(new_floating_plugin_action) => {
|
|
Ok(crate::input::actions::Action::NewFloatingPluginPane {
|
|
plugin: new_floating_plugin_action
|
|
.plugin
|
|
.ok_or_else(|| anyhow!("NewFloatingPluginPane missing plugin"))?
|
|
.try_into()?,
|
|
pane_name: new_floating_plugin_action.pane_name,
|
|
skip_cache: new_floating_plugin_action.skip_cache,
|
|
cwd: new_floating_plugin_action.cwd.map(PathBuf::from),
|
|
coordinates: new_floating_plugin_action
|
|
.coordinates
|
|
.map(|c| c.try_into())
|
|
.transpose()?,
|
|
no_focus: new_floating_plugin_action.no_focus,
|
|
tab_id: new_floating_plugin_action.tab_id.map(|t| t as usize),
|
|
})
|
|
},
|
|
ActionType::NewInPlacePluginPane(new_in_place_plugin_action) => {
|
|
Ok(crate::input::actions::Action::NewInPlacePluginPane {
|
|
plugin: new_in_place_plugin_action
|
|
.plugin
|
|
.ok_or_else(|| anyhow!("NewInPlacePluginPane missing plugin"))?
|
|
.try_into()?,
|
|
pane_name: new_in_place_plugin_action.pane_name,
|
|
skip_cache: new_in_place_plugin_action.skip_cache,
|
|
close_replaced_pane: new_in_place_plugin_action.close_replaced_pane,
|
|
no_focus: new_in_place_plugin_action.no_focus,
|
|
tab_id: new_in_place_plugin_action.tab_id.map(|t| t as usize),
|
|
})
|
|
},
|
|
ActionType::StartOrReloadPlugin(start_plugin_action) => {
|
|
Ok(crate::input::actions::Action::StartOrReloadPlugin {
|
|
plugin: start_plugin_action
|
|
.plugin
|
|
.ok_or_else(|| anyhow!("StartOrReloadPlugin missing plugin"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::CloseTerminalPane(close_pane_action) => {
|
|
Ok(crate::input::actions::Action::CloseTerminalPane {
|
|
pane_id: close_pane_action.pane_id,
|
|
})
|
|
},
|
|
ActionType::ClosePluginPane(close_pane_action) => {
|
|
Ok(crate::input::actions::Action::ClosePluginPane {
|
|
pane_id: close_pane_action.pane_id,
|
|
})
|
|
},
|
|
ActionType::FocusTerminalPaneWithId(focus_pane_action) => {
|
|
Ok(crate::input::actions::Action::FocusTerminalPaneWithId {
|
|
pane_id: focus_pane_action.pane_id,
|
|
should_float_if_hidden: focus_pane_action.should_float_if_hidden,
|
|
should_be_in_place_if_hidden: focus_pane_action.should_be_in_place_if_hidden,
|
|
})
|
|
},
|
|
ActionType::FocusPluginPaneWithId(focus_pane_action) => {
|
|
Ok(crate::input::actions::Action::FocusPluginPaneWithId {
|
|
pane_id: focus_pane_action.pane_id,
|
|
should_float_if_hidden: focus_pane_action.should_float_if_hidden,
|
|
should_be_in_place_if_hidden: focus_pane_action.should_be_in_place_if_hidden,
|
|
})
|
|
},
|
|
ActionType::RenameTerminalPane(rename_pane_action) => {
|
|
Ok(crate::input::actions::Action::RenameTerminalPane {
|
|
pane_id: rename_pane_action.pane_id,
|
|
name: rename_pane_action
|
|
.name
|
|
.into_iter()
|
|
.map(|b| b as u8)
|
|
.collect(),
|
|
})
|
|
},
|
|
ActionType::RenamePluginPane(rename_pane_action) => {
|
|
Ok(crate::input::actions::Action::RenamePluginPane {
|
|
pane_id: rename_pane_action.pane_id,
|
|
name: rename_pane_action
|
|
.name
|
|
.into_iter()
|
|
.map(|b| b as u8)
|
|
.collect(),
|
|
})
|
|
},
|
|
ActionType::RenameTab(rename_tab_action) => {
|
|
Ok(crate::input::actions::Action::RenameTab {
|
|
tab_index: rename_tab_action.tab_index,
|
|
name: rename_tab_action
|
|
.name
|
|
.into_iter()
|
|
.map(|b| b as u8)
|
|
.collect(),
|
|
})
|
|
},
|
|
ActionType::GoToTabById(go_to_tab_by_id_action) => {
|
|
Ok(crate::input::actions::Action::GoToTabById {
|
|
id: go_to_tab_by_id_action.id,
|
|
})
|
|
},
|
|
ActionType::CloseTabById(close_tab_by_id_action) => {
|
|
Ok(crate::input::actions::Action::CloseTabById {
|
|
id: close_tab_by_id_action.id,
|
|
})
|
|
},
|
|
ActionType::RenameTabById(rename_tab_by_id_action) => {
|
|
Ok(crate::input::actions::Action::RenameTabById {
|
|
id: rename_tab_by_id_action.id,
|
|
name: rename_tab_by_id_action.name,
|
|
})
|
|
},
|
|
ActionType::BreakPane(_) => Ok(crate::input::actions::Action::BreakPane),
|
|
ActionType::BreakPaneRight(_) => Ok(crate::input::actions::Action::BreakPaneRight),
|
|
ActionType::BreakPaneLeft(_) => Ok(crate::input::actions::Action::BreakPaneLeft),
|
|
ActionType::FocusHostSession(_) => Ok(crate::input::actions::Action::FocusHostSession),
|
|
ActionType::FocusGuestSession(_) => {
|
|
Ok(crate::input::actions::Action::FocusGuestSession)
|
|
},
|
|
ActionType::ToggleHostFullscreen(_) => {
|
|
Ok(crate::input::actions::Action::ToggleHostFullscreen)
|
|
},
|
|
ActionType::RenameSession(rename_session_action) => {
|
|
Ok(crate::input::actions::Action::RenameSession {
|
|
name: rename_session_action.name,
|
|
})
|
|
},
|
|
ActionType::CliPipe(cli_pipe_action) => Ok(crate::input::actions::Action::CliPipe {
|
|
pipe_id: cli_pipe_action.pipe_id,
|
|
name: cli_pipe_action.name,
|
|
payload: cli_pipe_action.payload,
|
|
args: if cli_pipe_action.args.is_empty() {
|
|
None
|
|
} else {
|
|
Some(cli_pipe_action.args.into_iter().collect())
|
|
},
|
|
plugin: cli_pipe_action.plugin,
|
|
configuration: if cli_pipe_action.configuration.is_empty() {
|
|
None
|
|
} else {
|
|
Some(cli_pipe_action.configuration.into_iter().collect())
|
|
},
|
|
launch_new: cli_pipe_action.launch_new,
|
|
skip_cache: cli_pipe_action.skip_cache,
|
|
floating: cli_pipe_action.floating,
|
|
in_place: cli_pipe_action.in_place,
|
|
cwd: cli_pipe_action.cwd.map(PathBuf::from),
|
|
pane_title: cli_pipe_action.pane_title,
|
|
popup: cli_pipe_action
|
|
.popup
|
|
.and_then(|p| p.parse::<crate::data::PipePopupPlacement>().ok()),
|
|
popup_no_focus: cli_pipe_action.popup_no_focus,
|
|
}),
|
|
ActionType::KeybindPipe(keybind_pipe_action) => {
|
|
Ok(crate::input::actions::Action::KeybindPipe {
|
|
name: keybind_pipe_action.name,
|
|
payload: keybind_pipe_action.payload,
|
|
args: if keybind_pipe_action.args.is_empty() {
|
|
None
|
|
} else {
|
|
Some(keybind_pipe_action.args.into_iter().collect())
|
|
},
|
|
plugin: keybind_pipe_action.plugin,
|
|
plugin_id: keybind_pipe_action.plugin_id,
|
|
configuration: if keybind_pipe_action.configuration.is_empty() {
|
|
None
|
|
} else {
|
|
Some(keybind_pipe_action.configuration.into_iter().collect())
|
|
},
|
|
launch_new: keybind_pipe_action.launch_new,
|
|
skip_cache: keybind_pipe_action.skip_cache,
|
|
floating: keybind_pipe_action.floating,
|
|
in_place: keybind_pipe_action.in_place,
|
|
cwd: keybind_pipe_action.cwd.map(PathBuf::from),
|
|
pane_title: keybind_pipe_action.pane_title,
|
|
})
|
|
},
|
|
ActionType::ListClients(_) => Ok(crate::input::actions::Action::ListClients),
|
|
ActionType::ListPanes(list_panes_action) => {
|
|
Ok(crate::input::actions::Action::ListPanes {
|
|
show_tab: list_panes_action.show_tab,
|
|
show_command: list_panes_action.show_command,
|
|
show_state: list_panes_action.show_state,
|
|
show_geometry: list_panes_action.show_geometry,
|
|
show_all: list_panes_action.show_all,
|
|
output_json: list_panes_action.output_json,
|
|
})
|
|
},
|
|
ActionType::ListTabs(list_tabs_action) => Ok(crate::input::actions::Action::ListTabs {
|
|
show_state: list_tabs_action.show_state,
|
|
show_dimensions: list_tabs_action.show_dimensions,
|
|
show_panes: list_tabs_action.show_panes,
|
|
show_layout: list_tabs_action.show_layout,
|
|
show_all: list_tabs_action.show_all,
|
|
output_json: list_tabs_action.output_json,
|
|
}),
|
|
ActionType::CurrentTabInfo(current_tab_info_action) => {
|
|
Ok(crate::input::actions::Action::CurrentTabInfo {
|
|
output_json: current_tab_info_action.output_json,
|
|
})
|
|
},
|
|
ActionType::TogglePanePinned(_) => Ok(crate::input::actions::Action::TogglePanePinned),
|
|
ActionType::StackPanes(stack_panes_action) => {
|
|
Ok(crate::input::actions::Action::StackPanes {
|
|
pane_ids: stack_panes_action
|
|
.pane_ids
|
|
.into_iter()
|
|
.map(|id| id.try_into())
|
|
.collect::<Result<Vec<_>>>()?,
|
|
})
|
|
},
|
|
ActionType::ChangeFloatingPaneCoordinates(change_coords_action) => Ok(
|
|
crate::input::actions::Action::ChangeFloatingPaneCoordinates {
|
|
pane_id: change_coords_action
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("ChangeFloatingPaneCoordinates missing pane_id"))?
|
|
.try_into()?,
|
|
coordinates: change_coords_action
|
|
.coordinates
|
|
.ok_or_else(|| {
|
|
anyhow!("ChangeFloatingPaneCoordinates missing coordinates")
|
|
})?
|
|
.try_into()?,
|
|
},
|
|
),
|
|
ActionType::TogglePaneBorderless(toggle_borderless_action) => {
|
|
Ok(crate::input::actions::Action::TogglePaneBorderless {
|
|
pane_id: toggle_borderless_action
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("TogglePaneBorderless missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::SetPaneBorderless(set_borderless_action) => {
|
|
Ok(crate::input::actions::Action::SetPaneBorderless {
|
|
pane_id: set_borderless_action
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("SetPaneBorderless missing pane_id"))?
|
|
.try_into()?,
|
|
borderless: set_borderless_action.borderless,
|
|
})
|
|
},
|
|
ActionType::SetPaneBorderStyle(set_border_style_action) => {
|
|
Ok(crate::input::actions::Action::SetPaneBorderStyle {
|
|
pane_id: set_border_style_action
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("SetPaneBorderStyle missing pane_id"))?
|
|
.try_into()?,
|
|
border_style: set_border_style_action
|
|
.border_style
|
|
.map(|b| b.into())
|
|
.unwrap_or_default(),
|
|
})
|
|
},
|
|
ActionType::TogglePaneInGroup(_) => {
|
|
Ok(crate::input::actions::Action::TogglePaneInGroup)
|
|
},
|
|
ActionType::ToggleGroupMarking(_) => {
|
|
Ok(crate::input::actions::Action::ToggleGroupMarking)
|
|
},
|
|
ActionType::SetPaneColor(set_pane_color_action) => {
|
|
Ok(crate::input::actions::Action::SetPaneColor {
|
|
pane_id: set_pane_color_action
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("SetPaneColor missing pane_id"))?
|
|
.try_into()?,
|
|
fg: set_pane_color_action.fg,
|
|
bg: set_pane_color_action.bg,
|
|
})
|
|
},
|
|
// Pane-targeting CLI-only variants
|
|
ActionType::ScrollUpByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::ScrollUpByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("ScrollUpByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::ScrollDownByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::ScrollDownByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("ScrollDownByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::ScrollToTopByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::ScrollToTopByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("ScrollToTopByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::ScrollToBottomByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::ScrollToBottomByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("ScrollToBottomByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::PageScrollUpByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::PageScrollUpByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("PageScrollUpByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::PageScrollDownByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::PageScrollDownByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("PageScrollDownByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::HalfPageScrollUpByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::HalfPageScrollUpByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("HalfPageScrollUpByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::HalfPageScrollDownByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::HalfPageScrollDownByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("HalfPageScrollDownByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::ResizeByPaneId(a) => {
|
|
let resize_action = a
|
|
.resize_action
|
|
.ok_or_else(|| anyhow!("ResizeByPaneId missing resize_action"))?;
|
|
let resize = proto_i32_to_resize(resize_action.resize)?;
|
|
let direction = resize_action
|
|
.direction
|
|
.map(|d| proto_i32_to_direction(d))
|
|
.transpose()?;
|
|
Ok(crate::input::actions::Action::ResizeByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("ResizeByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
resize,
|
|
direction,
|
|
})
|
|
},
|
|
ActionType::MovePaneByPaneId(a) => {
|
|
let direction = a.direction.map(|d| proto_i32_to_direction(d)).transpose()?;
|
|
Ok(crate::input::actions::Action::MovePaneByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("MovePaneByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
direction,
|
|
})
|
|
},
|
|
ActionType::MovePaneBackwardsByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::MovePaneBackwardsByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("MovePaneBackwardsByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::ClearScreenByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::ClearScreenByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("ClearScreenByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::EditScrollbackByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::EditScrollbackByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("EditScrollbackByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
ansi: a.ansi,
|
|
})
|
|
},
|
|
ActionType::ToggleFullscreenByPaneId(a) => Ok(
|
|
crate::input::actions::Action::ToggleFocusFullscreenByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("ToggleFullscreenByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
},
|
|
),
|
|
ActionType::ToggleNoUiFullscreenByPaneId(a) => Ok(
|
|
crate::input::actions::Action::ToggleFocusNoUiFullscreenByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("ToggleNoUiFullscreenByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
},
|
|
),
|
|
ActionType::TogglePaneEmbedOrFloatingByPaneId(a) => Ok(
|
|
crate::input::actions::Action::TogglePaneEmbedOrFloatingByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| {
|
|
anyhow!("TogglePaneEmbedOrFloatingByPaneId missing pane_id")
|
|
})?
|
|
.try_into()?,
|
|
},
|
|
),
|
|
ActionType::CloseFocusByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::CloseFocusByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("CloseFocusByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::RenamePaneByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::RenamePaneByPaneId {
|
|
pane_id: a.pane_id.map(|p| p.try_into()).transpose()?,
|
|
name: a.name,
|
|
})
|
|
},
|
|
ActionType::UndoRenamePaneByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::UndoRenamePaneByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("UndoRenamePaneByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::TogglePanePinnedByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::TogglePanePinnedByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("TogglePanePinnedByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::TogglePaneInGroupByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::TogglePaneInGroupByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("TogglePaneInGroupByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::StartRenamePaneByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::StartRenamePaneByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("StartRenamePaneByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
ActionType::StartRenameTabByTabId(a) => {
|
|
Ok(crate::input::actions::Action::StartRenameTabByTabId { id: a.id })
|
|
},
|
|
ActionType::FocusPaneByPaneId(a) => {
|
|
Ok(crate::input::actions::Action::FocusPaneByPaneId {
|
|
pane_id: a
|
|
.pane_id
|
|
.ok_or_else(|| anyhow!("FocusPaneByPaneId missing pane_id"))?
|
|
.try_into()?,
|
|
})
|
|
},
|
|
// Tab-targeting CLI-only variants
|
|
ActionType::UndoRenameTabByTabId(a) => {
|
|
Ok(crate::input::actions::Action::UndoRenameTabByTabId { id: a.id })
|
|
},
|
|
ActionType::ToggleActiveSyncTabByTabId(a) => {
|
|
Ok(crate::input::actions::Action::ToggleActiveSyncTabByTabId { id: a.id })
|
|
},
|
|
ActionType::ToggleFloatingPanesByTabId(a) => {
|
|
Ok(crate::input::actions::Action::ToggleFloatingPanesByTabId { id: a.id })
|
|
},
|
|
ActionType::PreviousSwapLayoutByTabId(a) => {
|
|
Ok(crate::input::actions::Action::PreviousSwapLayoutByTabId { id: a.id })
|
|
},
|
|
ActionType::NextSwapLayoutByTabId(a) => {
|
|
Ok(crate::input::actions::Action::NextSwapLayoutByTabId { id: a.id })
|
|
},
|
|
ActionType::ApplyTiledSwapLayoutByTabId(a) => {
|
|
Ok(crate::input::actions::Action::ApplyTiledSwapLayoutByTabId {
|
|
id: a.id,
|
|
name: a.name,
|
|
})
|
|
},
|
|
ActionType::ApplyFloatingSwapLayoutByTabId(a) => Ok(
|
|
crate::input::actions::Action::ApplyFloatingSwapLayoutByTabId {
|
|
id: a.id,
|
|
name: a.name,
|
|
},
|
|
),
|
|
ActionType::MoveTabByTabId(a) => {
|
|
let direction = proto_i32_to_direction(a.direction)?;
|
|
Ok(crate::input::actions::Action::MoveTabByTabId {
|
|
id: a.id,
|
|
direction,
|
|
})
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<crate::data::KeyWithModifier>
|
|
for crate::client_server_contract::client_server_contract::KeyWithModifier
|
|
{
|
|
fn from(key: crate::data::KeyWithModifier) -> Self {
|
|
use crate::ipc::enum_conversions::{bare_key_to_proto_i32, key_modifier_to_proto_i32};
|
|
|
|
// Handle character keys specially - store the character for Char variant
|
|
let (bare_key_enum, char_data) = match &key.bare_key {
|
|
crate::data::BareKey::Char(c) => (
|
|
crate::client_server_contract::client_server_contract::BareKey::Char as i32,
|
|
Some(c.to_string()),
|
|
),
|
|
other => (bare_key_to_proto_i32(*other), None),
|
|
};
|
|
|
|
Self {
|
|
bare_key: bare_key_enum,
|
|
key_modifiers: key
|
|
.key_modifiers
|
|
.into_iter()
|
|
.map(|modifier| key_modifier_to_proto_i32(modifier))
|
|
.collect(),
|
|
character: char_data,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::KeyWithModifier>
|
|
for crate::data::KeyWithModifier
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
key: crate::client_server_contract::client_server_contract::KeyWithModifier,
|
|
) -> Result<Self> {
|
|
use crate::ipc::enum_conversions::{bare_key_from_proto_i32, key_modifier_from_proto_i32};
|
|
use std::collections::BTreeSet;
|
|
|
|
// Handle character keys specially
|
|
let bare_key = if key.bare_key
|
|
== crate::client_server_contract::client_server_contract::BareKey::Char as i32
|
|
{
|
|
let character_str = key
|
|
.character
|
|
.ok_or_else(|| anyhow!("Character key missing character data"))?;
|
|
let character = character_str
|
|
.chars()
|
|
.next()
|
|
.ok_or_else(|| anyhow!("Empty character string"))?;
|
|
crate::data::BareKey::Char(character)
|
|
} else {
|
|
bare_key_from_proto_i32(key.bare_key)?
|
|
};
|
|
|
|
let key_modifiers: Result<BTreeSet<_>> = key
|
|
.key_modifiers
|
|
.into_iter()
|
|
.map(|modifier| key_modifier_from_proto_i32(modifier))
|
|
.collect();
|
|
|
|
Ok(Self {
|
|
bare_key,
|
|
key_modifiers: key_modifiers?,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<crate::data::ConnectToSession>
|
|
for crate::client_server_contract::client_server_contract::ConnectToSession
|
|
{
|
|
fn from(connect: crate::data::ConnectToSession) -> Self {
|
|
Self {
|
|
name: connect.name,
|
|
tab_position: connect.tab_position.map(|p| p as u32),
|
|
pane_id: connect.pane_id.map(|(id, is_plugin)| {
|
|
crate::client_server_contract::client_server_contract::PaneIdWithPlugin {
|
|
pane_id: id,
|
|
is_plugin,
|
|
}
|
|
}),
|
|
layout: connect.layout.map(|l| l.into()),
|
|
cwd: connect.cwd.map(|p| p.to_string_lossy().to_string()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::ConnectToSession>
|
|
for crate::data::ConnectToSession
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
connect: crate::client_server_contract::client_server_contract::ConnectToSession,
|
|
) -> Result<Self> {
|
|
Ok(Self {
|
|
name: connect.name,
|
|
tab_position: connect.tab_position.map(|p| p as usize),
|
|
pane_id: connect.pane_id.map(|p| (p.pane_id, p.is_plugin)),
|
|
layout: connect.layout.map(|l| l.try_into()).transpose()?,
|
|
cwd: connect.cwd.map(PathBuf::from),
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<crate::data::LayoutInfo>
|
|
for crate::client_server_contract::client_server_contract::LayoutInfo
|
|
{
|
|
fn from(layout: crate::data::LayoutInfo) -> Self {
|
|
use crate::client_server_contract::client_server_contract::layout_info::LayoutType;
|
|
let (layout_type, layout_metadata) = match layout {
|
|
crate::data::LayoutInfo::BuiltIn(name) => (LayoutType::BuiltinName(name), None),
|
|
crate::data::LayoutInfo::File(path, metadata) => {
|
|
(LayoutType::FilePath(path), Some(metadata.into()))
|
|
},
|
|
crate::data::LayoutInfo::Url(url) => (LayoutType::Url(url), None),
|
|
crate::data::LayoutInfo::Stringified(content) => {
|
|
(LayoutType::Stringified(content), None)
|
|
},
|
|
};
|
|
Self {
|
|
layout_type: Some(layout_type),
|
|
layout_metadata,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::LayoutInfo>
|
|
for crate::data::LayoutInfo
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
layout: crate::client_server_contract::client_server_contract::LayoutInfo,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::layout_info::LayoutType;
|
|
match layout.layout_type {
|
|
Some(LayoutType::BuiltinName(name)) => Ok(crate::data::LayoutInfo::BuiltIn(name)),
|
|
Some(LayoutType::FilePath(path)) => {
|
|
let layout_metadata = layout
|
|
.layout_metadata
|
|
.map(|m| m.try_into())
|
|
.transpose()?
|
|
.unwrap_or_default();
|
|
Ok(crate::data::LayoutInfo::File(path, layout_metadata))
|
|
},
|
|
Some(LayoutType::Url(url)) => Ok(crate::data::LayoutInfo::Url(url)),
|
|
Some(LayoutType::Stringified(content)) => {
|
|
Ok(crate::data::LayoutInfo::Stringified(content))
|
|
},
|
|
None => Err(anyhow!("LayoutInfo missing layout_type")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<crate::data::LayoutMetadata> for ProtoLayoutMetadata {
|
|
fn from(metadata: crate::data::LayoutMetadata) -> Self {
|
|
ProtoLayoutMetadata {
|
|
tabs: metadata.tabs.into_iter().map(|t| t.into()).collect(),
|
|
creation_time: metadata.creation_time,
|
|
update_time: metadata.update_time,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<ProtoLayoutMetadata> for crate::data::LayoutMetadata {
|
|
type Error = anyhow::Error;
|
|
fn try_from(proto_metadata: ProtoLayoutMetadata) -> Result<Self> {
|
|
let tabs = proto_metadata
|
|
.tabs
|
|
.into_iter()
|
|
.map(|t| t.try_into())
|
|
.collect::<Result<Vec<_>>>()?;
|
|
Ok(crate::data::LayoutMetadata {
|
|
tabs,
|
|
creation_time: proto_metadata.creation_time,
|
|
update_time: proto_metadata.update_time,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<crate::data::TabMetadata> for ProtoTabMetadata {
|
|
fn from(metadata: crate::data::TabMetadata) -> Self {
|
|
ProtoTabMetadata {
|
|
pane_metadata: metadata.panes.into_iter().map(|p| p.into()).collect(),
|
|
name: metadata.name,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<ProtoTabMetadata> for crate::data::TabMetadata {
|
|
type Error = anyhow::Error;
|
|
fn try_from(proto_metadata: ProtoTabMetadata) -> Result<Self> {
|
|
let panes = proto_metadata
|
|
.pane_metadata
|
|
.into_iter()
|
|
.map(|p| p.try_into())
|
|
.collect::<Result<Vec<_>>>()?;
|
|
Ok(crate::data::TabMetadata {
|
|
panes,
|
|
name: proto_metadata.name,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<crate::data::PaneMetadata> for ProtoPaneMetadata {
|
|
fn from(metadata: crate::data::PaneMetadata) -> Self {
|
|
ProtoPaneMetadata {
|
|
name: metadata.name,
|
|
is_plugin: metadata.is_plugin,
|
|
is_builtin_plugin: metadata.is_builtin_plugin,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<ProtoPaneMetadata> for crate::data::PaneMetadata {
|
|
type Error = anyhow::Error;
|
|
fn try_from(proto_metadata: ProtoPaneMetadata) -> Result<Self> {
|
|
Ok(crate::data::PaneMetadata {
|
|
name: proto_metadata.name,
|
|
is_plugin: proto_metadata.is_plugin,
|
|
is_builtin_plugin: proto_metadata.is_builtin_plugin,
|
|
})
|
|
}
|
|
}
|
|
|
|
impl From<ExitReason> for ProtoExitReason {
|
|
fn from(reason: ExitReason) -> Self {
|
|
match reason {
|
|
ExitReason::Normal => ProtoExitReason::Normal,
|
|
ExitReason::NormalDetached => ProtoExitReason::NormalDetached,
|
|
ExitReason::ForceDetached => ProtoExitReason::ForceDetached,
|
|
ExitReason::CannotAttach => ProtoExitReason::CannotAttach,
|
|
ExitReason::Disconnect => ProtoExitReason::Disconnect,
|
|
ExitReason::WebClientsForbidden => ProtoExitReason::WebClientsForbidden,
|
|
ExitReason::KickedByHost => ProtoExitReason::KickedByHost,
|
|
ExitReason::Error(_msg) => ProtoExitReason::Error,
|
|
ExitReason::CustomExitStatus(_status) => ProtoExitReason::CustomExitStatus,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<ProtoExitReason> for ExitReason {
|
|
type Error = anyhow::Error;
|
|
fn try_from(reason: ProtoExitReason) -> Result<Self> {
|
|
match reason {
|
|
ProtoExitReason::Normal => Ok(ExitReason::Normal),
|
|
ProtoExitReason::NormalDetached => Ok(ExitReason::NormalDetached),
|
|
ProtoExitReason::ForceDetached => Ok(ExitReason::ForceDetached),
|
|
ProtoExitReason::CannotAttach => Ok(ExitReason::CannotAttach),
|
|
ProtoExitReason::Disconnect => Ok(ExitReason::Disconnect),
|
|
ProtoExitReason::WebClientsForbidden => Ok(ExitReason::WebClientsForbidden),
|
|
ProtoExitReason::KickedByHost => Ok(ExitReason::KickedByHost),
|
|
ProtoExitReason::Error => Ok(ExitReason::Error("Protobuf error".to_string())),
|
|
ProtoExitReason::CustomExitStatus => Ok(ExitReason::CustomExitStatus(0)),
|
|
ProtoExitReason::Unspecified => Err(anyhow!("Unspecified exit reason")),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<HostTerminalThemeMode> for ProtoHostTerminalThemeIndication {
|
|
fn from(mode: HostTerminalThemeMode) -> Self {
|
|
match mode {
|
|
HostTerminalThemeMode::Dark => ProtoHostTerminalThemeIndication::Dark,
|
|
HostTerminalThemeMode::Light => ProtoHostTerminalThemeIndication::Light,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<ProtoHostTerminalThemeIndication> for HostTerminalThemeMode {
|
|
fn from(mode: ProtoHostTerminalThemeIndication) -> Self {
|
|
match mode {
|
|
ProtoHostTerminalThemeIndication::Dark => HostTerminalThemeMode::Dark,
|
|
ProtoHostTerminalThemeIndication::Light => HostTerminalThemeMode::Light,
|
|
}
|
|
}
|
|
}
|
|
|
|
// InputMode conversion helper functions
|
|
fn input_mode_to_proto_i32(mode: InputMode) -> i32 {
|
|
match mode {
|
|
InputMode::Normal => ProtoInputMode::Normal as i32,
|
|
InputMode::Locked => ProtoInputMode::Locked as i32,
|
|
InputMode::Resize => ProtoInputMode::Resize as i32,
|
|
InputMode::Pane => ProtoInputMode::Pane as i32,
|
|
InputMode::Tab => ProtoInputMode::Tab as i32,
|
|
InputMode::Scroll => ProtoInputMode::Scroll as i32,
|
|
InputMode::EnterSearch => ProtoInputMode::EnterSearch as i32,
|
|
InputMode::Search => ProtoInputMode::Search as i32,
|
|
InputMode::RenameTab => ProtoInputMode::RenameTab as i32,
|
|
InputMode::RenamePane => ProtoInputMode::RenamePane as i32,
|
|
InputMode::Session => ProtoInputMode::Session as i32,
|
|
InputMode::Move => ProtoInputMode::Move as i32,
|
|
InputMode::Prompt => ProtoInputMode::Prompt as i32,
|
|
InputMode::Tmux => ProtoInputMode::Tmux as i32,
|
|
}
|
|
}
|
|
|
|
fn proto_i32_to_input_mode(i: i32) -> Result<InputMode> {
|
|
match ProtoInputMode::try_from(i).ok() {
|
|
Some(ProtoInputMode::Normal) => Ok(InputMode::Normal),
|
|
Some(ProtoInputMode::Locked) => Ok(InputMode::Locked),
|
|
Some(ProtoInputMode::Resize) => Ok(InputMode::Resize),
|
|
Some(ProtoInputMode::Pane) => Ok(InputMode::Pane),
|
|
Some(ProtoInputMode::Tab) => Ok(InputMode::Tab),
|
|
Some(ProtoInputMode::Scroll) => Ok(InputMode::Scroll),
|
|
Some(ProtoInputMode::EnterSearch) => Ok(InputMode::EnterSearch),
|
|
Some(ProtoInputMode::Search) => Ok(InputMode::Search),
|
|
Some(ProtoInputMode::RenameTab) => Ok(InputMode::RenameTab),
|
|
Some(ProtoInputMode::RenamePane) => Ok(InputMode::RenamePane),
|
|
Some(ProtoInputMode::Session) => Ok(InputMode::Session),
|
|
Some(ProtoInputMode::Move) => Ok(InputMode::Move),
|
|
Some(ProtoInputMode::Prompt) => Ok(InputMode::Prompt),
|
|
Some(ProtoInputMode::Tmux) => Ok(InputMode::Tmux),
|
|
_ => Err(anyhow!("Invalid InputMode value: {}", i)),
|
|
}
|
|
}
|
|
|
|
// Additional helper functions for Action conversion
|
|
fn resize_to_proto_i32(resize: crate::data::Resize) -> i32 {
|
|
use crate::client_server_contract::client_server_contract::ResizeType;
|
|
match resize {
|
|
crate::data::Resize::Increase => ResizeType::Increase as i32,
|
|
crate::data::Resize::Decrease => ResizeType::Decrease as i32,
|
|
}
|
|
}
|
|
|
|
fn direction_to_proto_i32(direction: crate::data::Direction) -> i32 {
|
|
use crate::client_server_contract::client_server_contract::Direction as ProtoDirection;
|
|
match direction {
|
|
crate::data::Direction::Left => ProtoDirection::Left as i32,
|
|
crate::data::Direction::Right => ProtoDirection::Right as i32,
|
|
crate::data::Direction::Up => ProtoDirection::Up as i32,
|
|
crate::data::Direction::Down => ProtoDirection::Down as i32,
|
|
}
|
|
}
|
|
|
|
fn search_direction_to_proto_i32(direction: crate::input::actions::SearchDirection) -> i32 {
|
|
use crate::client_server_contract::client_server_contract::SearchDirection as ProtoSearchDirection;
|
|
match direction {
|
|
crate::input::actions::SearchDirection::Up => ProtoSearchDirection::Up as i32,
|
|
crate::input::actions::SearchDirection::Down => ProtoSearchDirection::Down as i32,
|
|
}
|
|
}
|
|
|
|
fn search_option_to_proto_i32(option: crate::input::actions::SearchOption) -> i32 {
|
|
use crate::client_server_contract::client_server_contract::SearchOption as ProtoSearchOption;
|
|
match option {
|
|
crate::input::actions::SearchOption::CaseSensitivity => {
|
|
ProtoSearchOption::CaseSensitivity as i32
|
|
},
|
|
crate::input::actions::SearchOption::Wrap => ProtoSearchOption::Wrap as i32,
|
|
crate::input::actions::SearchOption::WholeWord => ProtoSearchOption::WholeWord as i32,
|
|
}
|
|
}
|
|
|
|
fn unblock_condition_to_proto_i32(condition: crate::data::UnblockCondition) -> i32 {
|
|
use crate::client_server_contract::client_server_contract::UnblockCondition as ProtoUnblockCondition;
|
|
match condition {
|
|
crate::data::UnblockCondition::OnExitSuccess => ProtoUnblockCondition::OnExitSuccess as i32,
|
|
crate::data::UnblockCondition::OnExitFailure => ProtoUnblockCondition::OnExitFailure as i32,
|
|
crate::data::UnblockCondition::OnAnyExit => ProtoUnblockCondition::OnAnyExit as i32,
|
|
}
|
|
}
|
|
|
|
// Reverse helper functions for Action conversion
|
|
|
|
fn proto_i32_to_resize(resize: i32) -> Result<crate::data::Resize> {
|
|
use crate::client_server_contract::client_server_contract::ResizeType as ProtoResize;
|
|
let proto_resize = match resize {
|
|
x if x == ProtoResize::Increase as i32 => ProtoResize::Increase,
|
|
x if x == ProtoResize::Decrease as i32 => ProtoResize::Decrease,
|
|
_ => return Err(anyhow!("Invalid ResizeType: {}", resize)),
|
|
};
|
|
match proto_resize {
|
|
ProtoResize::Increase => Ok(crate::data::Resize::Increase),
|
|
ProtoResize::Decrease => Ok(crate::data::Resize::Decrease),
|
|
ProtoResize::Unspecified => Err(anyhow!("Unspecified ResizeType")),
|
|
}
|
|
}
|
|
|
|
fn proto_i32_to_direction(direction: i32) -> Result<crate::data::Direction> {
|
|
use crate::client_server_contract::client_server_contract::Direction as ProtoDirection;
|
|
let proto_direction = match direction {
|
|
x if x == ProtoDirection::Left as i32 => ProtoDirection::Left,
|
|
x if x == ProtoDirection::Right as i32 => ProtoDirection::Right,
|
|
x if x == ProtoDirection::Up as i32 => ProtoDirection::Up,
|
|
x if x == ProtoDirection::Down as i32 => ProtoDirection::Down,
|
|
_ => return Err(anyhow!("Invalid Direction: {}", direction)),
|
|
};
|
|
match proto_direction {
|
|
ProtoDirection::Left => Ok(crate::data::Direction::Left),
|
|
ProtoDirection::Right => Ok(crate::data::Direction::Right),
|
|
ProtoDirection::Up => Ok(crate::data::Direction::Up),
|
|
ProtoDirection::Down => Ok(crate::data::Direction::Down),
|
|
ProtoDirection::Unspecified => Err(anyhow!("Unspecified direction")),
|
|
}
|
|
}
|
|
|
|
fn proto_i32_to_search_direction(direction: i32) -> Result<crate::input::actions::SearchDirection> {
|
|
use crate::client_server_contract::client_server_contract::SearchDirection as ProtoSearchDirection;
|
|
let proto_direction = match direction {
|
|
x if x == ProtoSearchDirection::Up as i32 => ProtoSearchDirection::Up,
|
|
x if x == ProtoSearchDirection::Down as i32 => ProtoSearchDirection::Down,
|
|
_ => return Err(anyhow!("Invalid SearchDirection: {}", direction)),
|
|
};
|
|
match proto_direction {
|
|
ProtoSearchDirection::Up => Ok(crate::input::actions::SearchDirection::Up),
|
|
ProtoSearchDirection::Down => Ok(crate::input::actions::SearchDirection::Down),
|
|
ProtoSearchDirection::Unspecified => Err(anyhow!("Unspecified search direction")),
|
|
}
|
|
}
|
|
|
|
fn proto_i32_to_search_option(option: i32) -> Result<crate::input::actions::SearchOption> {
|
|
use crate::client_server_contract::client_server_contract::SearchOption as ProtoSearchOption;
|
|
let proto_option = match option {
|
|
x if x == ProtoSearchOption::CaseSensitivity as i32 => ProtoSearchOption::CaseSensitivity,
|
|
x if x == ProtoSearchOption::WholeWord as i32 => ProtoSearchOption::WholeWord,
|
|
x if x == ProtoSearchOption::Wrap as i32 => ProtoSearchOption::Wrap,
|
|
_ => return Err(anyhow!("Invalid SearchOption: {}", option)),
|
|
};
|
|
match proto_option {
|
|
ProtoSearchOption::CaseSensitivity => {
|
|
Ok(crate::input::actions::SearchOption::CaseSensitivity)
|
|
},
|
|
ProtoSearchOption::Wrap => Ok(crate::input::actions::SearchOption::Wrap),
|
|
ProtoSearchOption::WholeWord => Ok(crate::input::actions::SearchOption::WholeWord),
|
|
ProtoSearchOption::Unspecified => Err(anyhow!("Unspecified search option")),
|
|
}
|
|
}
|
|
|
|
fn proto_i32_to_unblock_condition(condition: i32) -> Result<crate::data::UnblockCondition> {
|
|
use crate::client_server_contract::client_server_contract::UnblockCondition as ProtoUnblockCondition;
|
|
let proto_condition = match condition {
|
|
x if x == ProtoUnblockCondition::OnExitSuccess as i32 => {
|
|
ProtoUnblockCondition::OnExitSuccess
|
|
},
|
|
x if x == ProtoUnblockCondition::OnExitFailure as i32 => {
|
|
ProtoUnblockCondition::OnExitFailure
|
|
},
|
|
x if x == ProtoUnblockCondition::OnAnyExit as i32 => ProtoUnblockCondition::OnAnyExit,
|
|
_ => return Err(anyhow!("Invalid UnblockCondition: {}", condition)),
|
|
};
|
|
match proto_condition {
|
|
ProtoUnblockCondition::OnExitSuccess => Ok(crate::data::UnblockCondition::OnExitSuccess),
|
|
ProtoUnblockCondition::OnExitFailure => Ok(crate::data::UnblockCondition::OnExitFailure),
|
|
ProtoUnblockCondition::OnAnyExit => Ok(crate::data::UnblockCondition::OnAnyExit),
|
|
ProtoUnblockCondition::Unspecified => Err(anyhow!("Unspecified unblock condition")),
|
|
}
|
|
}
|
|
|
|
// Position conversion
|
|
impl From<crate::position::Position>
|
|
for crate::client_server_contract::client_server_contract::Position
|
|
{
|
|
fn from(pos: crate::position::Position) -> Self {
|
|
Self {
|
|
line: pos.line.0 as i32,
|
|
column: pos.column.0 as u64,
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reverse Position conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::Position>
|
|
for crate::position::Position
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
pos: crate::client_server_contract::client_server_contract::Position,
|
|
) -> Result<Self> {
|
|
Ok(Self {
|
|
line: crate::position::Line(pos.line as isize),
|
|
column: crate::position::Column(pos.column as usize),
|
|
})
|
|
}
|
|
}
|
|
|
|
// OpenFilePayload conversion
|
|
impl From<crate::input::command::OpenFilePayload>
|
|
for crate::client_server_contract::client_server_contract::OpenFilePayload
|
|
{
|
|
fn from(payload: crate::input::command::OpenFilePayload) -> Self {
|
|
Self {
|
|
file_to_open: payload.path.to_string_lossy().to_string(),
|
|
line_number: payload.line_number.map(|n| n as u32),
|
|
cwd: payload.cwd.map(|p| p.to_string_lossy().to_string()),
|
|
originating_plugin: payload.originating_plugin.map(|op| op.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reverse OpenFilePayload conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::OpenFilePayload>
|
|
for crate::input::command::OpenFilePayload
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
payload: crate::client_server_contract::client_server_contract::OpenFilePayload,
|
|
) -> Result<Self> {
|
|
Ok(Self {
|
|
path: PathBuf::from(payload.file_to_open),
|
|
line_number: payload.line_number.map(|n| n as usize),
|
|
cwd: payload.cwd.map(PathBuf::from),
|
|
originating_plugin: payload
|
|
.originating_plugin
|
|
.map(|op| op.try_into())
|
|
.transpose()?,
|
|
})
|
|
}
|
|
}
|
|
|
|
// PaneId conversion
|
|
impl From<crate::data::PaneId> for crate::client_server_contract::client_server_contract::PaneId {
|
|
fn from(pane_id: crate::data::PaneId) -> Self {
|
|
use crate::client_server_contract::client_server_contract::pane_id::PaneType;
|
|
match pane_id {
|
|
crate::data::PaneId::Terminal(id) => Self {
|
|
pane_type: Some(PaneType::Terminal(id)),
|
|
},
|
|
crate::data::PaneId::Plugin(id) => Self {
|
|
pane_type: Some(PaneType::Plugin(id)),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reverse PaneId conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::PaneId>
|
|
for crate::data::PaneId
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
pane_id: crate::client_server_contract::client_server_contract::PaneId,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::pane_id::PaneType;
|
|
match pane_id
|
|
.pane_type
|
|
.ok_or_else(|| anyhow!("PaneId missing pane_type"))?
|
|
{
|
|
PaneType::Terminal(id) => Ok(crate::data::PaneId::Terminal(id)),
|
|
PaneType::Plugin(id) => Ok(crate::data::PaneId::Plugin(id)),
|
|
}
|
|
}
|
|
}
|
|
|
|
// FloatingCoordinate conversion - SplitSize to FloatingCoordinate
|
|
impl From<crate::input::layout::SplitSize>
|
|
for crate::client_server_contract::client_server_contract::FloatingCoordinate
|
|
{
|
|
fn from(size: crate::input::layout::SplitSize) -> Self {
|
|
match size {
|
|
crate::input::layout::SplitSize::Percent(p) => Self {
|
|
coordinate_type: Some(crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType::Percent(p as f32)),
|
|
},
|
|
crate::input::layout::SplitSize::Fixed(f) => Self {
|
|
coordinate_type: Some(crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType::Fixed(f as u32)),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reverse FloatingCoordinate conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::FloatingCoordinate>
|
|
for crate::input::layout::SplitSize
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
coord: crate::client_server_contract::client_server_contract::FloatingCoordinate,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType;
|
|
match coord
|
|
.coordinate_type
|
|
.ok_or_else(|| anyhow!("FloatingCoordinate missing coordinate_type"))?
|
|
{
|
|
CoordinateType::Percent(p) => Ok(crate::input::layout::SplitSize::Percent(p as usize)),
|
|
CoordinateType::Fixed(f) => Ok(crate::input::layout::SplitSize::Fixed(f as usize)),
|
|
}
|
|
}
|
|
}
|
|
|
|
// FloatingCoordinate conversion - PercentOrFixed to FloatingCoordinate
|
|
impl From<crate::input::layout::PercentOrFixed>
|
|
for crate::client_server_contract::client_server_contract::FloatingCoordinate
|
|
{
|
|
fn from(size: crate::input::layout::PercentOrFixed) -> Self {
|
|
match size {
|
|
crate::input::layout::PercentOrFixed::Percent(p) => Self {
|
|
coordinate_type: Some(crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType::Percent(p as f32)),
|
|
},
|
|
crate::input::layout::PercentOrFixed::Fixed(f) => Self {
|
|
coordinate_type: Some(crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType::Fixed(f as u32)),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reverse FloatingCoordinate conversion for PercentOrFixed
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::FloatingCoordinate>
|
|
for crate::input::layout::PercentOrFixed
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
coord: crate::client_server_contract::client_server_contract::FloatingCoordinate,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::floating_coordinate::CoordinateType;
|
|
match coord
|
|
.coordinate_type
|
|
.ok_or_else(|| anyhow!("FloatingCoordinate missing coordinate_type"))?
|
|
{
|
|
CoordinateType::Percent(p) => {
|
|
Ok(crate::input::layout::PercentOrFixed::Percent(p as usize))
|
|
},
|
|
CoordinateType::Fixed(f) => Ok(crate::input::layout::PercentOrFixed::Fixed(f as usize)),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn line_style_to_proto_i32(line_style: crate::data::LineStyle) -> i32 {
|
|
use crate::client_server_contract::client_server_contract::LineStyle as ProtoLineStyle;
|
|
let proto = match line_style {
|
|
crate::data::LineStyle::Single => ProtoLineStyle::Single,
|
|
crate::data::LineStyle::Double => ProtoLineStyle::Double,
|
|
crate::data::LineStyle::Heavy => ProtoLineStyle::Heavy,
|
|
crate::data::LineStyle::Dashed => ProtoLineStyle::Dashed,
|
|
crate::data::LineStyle::HeavyDashed => ProtoLineStyle::HeavyDashed,
|
|
};
|
|
proto as i32
|
|
}
|
|
|
|
fn proto_i32_to_line_style(value: i32) -> crate::data::LineStyle {
|
|
use crate::client_server_contract::client_server_contract::LineStyle as ProtoLineStyle;
|
|
match ProtoLineStyle::try_from(value) {
|
|
Ok(ProtoLineStyle::Single) => crate::data::LineStyle::Single,
|
|
Ok(ProtoLineStyle::Double) => crate::data::LineStyle::Double,
|
|
Ok(ProtoLineStyle::Heavy) => crate::data::LineStyle::Heavy,
|
|
Ok(ProtoLineStyle::Dashed) => crate::data::LineStyle::Dashed,
|
|
Ok(ProtoLineStyle::HeavyDashed) => crate::data::LineStyle::HeavyDashed,
|
|
Err(_) => crate::data::LineStyle::Single,
|
|
}
|
|
}
|
|
|
|
impl From<crate::data::BorderStyleOverride>
|
|
for crate::client_server_contract::client_server_contract::BorderStyleOverride
|
|
{
|
|
fn from(border_style: crate::data::BorderStyleOverride) -> Self {
|
|
Self {
|
|
all: border_style.all.map(line_style_to_proto_i32),
|
|
top: border_style.top.map(line_style_to_proto_i32),
|
|
right: border_style.right.map(line_style_to_proto_i32),
|
|
bottom: border_style.bottom.map(line_style_to_proto_i32),
|
|
left: border_style.left.map(line_style_to_proto_i32),
|
|
rounded_corners: border_style.rounded_corners,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<crate::client_server_contract::client_server_contract::BorderStyleOverride>
|
|
for crate::data::BorderStyleOverride
|
|
{
|
|
fn from(
|
|
border_style: crate::client_server_contract::client_server_contract::BorderStyleOverride,
|
|
) -> Self {
|
|
Self {
|
|
all: border_style.all.map(proto_i32_to_line_style),
|
|
top: border_style.top.map(proto_i32_to_line_style),
|
|
right: border_style.right.map(proto_i32_to_line_style),
|
|
bottom: border_style.bottom.map(proto_i32_to_line_style),
|
|
left: border_style.left.map(proto_i32_to_line_style),
|
|
rounded_corners: border_style.rounded_corners,
|
|
}
|
|
}
|
|
}
|
|
|
|
// FloatingPaneCoordinates conversion
|
|
impl From<crate::data::FloatingPaneCoordinates>
|
|
for crate::client_server_contract::client_server_contract::FloatingPaneCoordinates
|
|
{
|
|
fn from(coords: crate::data::FloatingPaneCoordinates) -> Self {
|
|
Self {
|
|
x: coords.x.map(|x| x.into()),
|
|
y: coords.y.map(|y| y.into()),
|
|
width: coords.width.map(|w| w.into()),
|
|
height: coords.height.map(|h| h.into()),
|
|
pinned: coords.pinned,
|
|
borderless: coords.borderless,
|
|
border_style: coords.border_style.map(|b| b.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reverse FloatingPaneCoordinates conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::FloatingPaneCoordinates>
|
|
for crate::data::FloatingPaneCoordinates
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
coords: crate::client_server_contract::client_server_contract::FloatingPaneCoordinates,
|
|
) -> Result<Self> {
|
|
Ok(Self {
|
|
x: coords.x.map(|x| x.try_into()).transpose()?,
|
|
y: coords.y.map(|y| y.try_into()).transpose()?,
|
|
width: coords.width.map(|w| w.try_into()).transpose()?,
|
|
height: coords.height.map(|h| h.try_into()).transpose()?,
|
|
pinned: coords.pinned,
|
|
borderless: coords.borderless,
|
|
border_style: coords.border_style.map(|b| b.into()),
|
|
})
|
|
}
|
|
}
|
|
|
|
// NewPanePlacement conversion
|
|
impl From<crate::data::NewPanePlacement>
|
|
for crate::client_server_contract::client_server_contract::NewPanePlacement
|
|
{
|
|
fn from(placement: crate::data::NewPanePlacement) -> Self {
|
|
use crate::client_server_contract::client_server_contract::new_pane_placement::PlacementType;
|
|
use crate::client_server_contract::client_server_contract::{
|
|
NoPreferencePlacement, StackedPlacement, TiledPlacement,
|
|
};
|
|
let placement_type = match placement {
|
|
crate::data::NewPanePlacement::NoPreference {
|
|
borderless: None,
|
|
border_style: None,
|
|
} => PlacementType::NoPreference(true),
|
|
crate::data::NewPanePlacement::NoPreference {
|
|
borderless,
|
|
border_style,
|
|
} => PlacementType::NoPreferenceWithOptions(NoPreferencePlacement {
|
|
borderless,
|
|
border_style: border_style.map(|b| b.into()),
|
|
}),
|
|
crate::data::NewPanePlacement::Tiled {
|
|
direction,
|
|
borderless: None,
|
|
border_style: None,
|
|
} => PlacementType::Tiled(direction.map(direction_to_proto_i32).unwrap_or(0)),
|
|
crate::data::NewPanePlacement::Tiled {
|
|
direction,
|
|
borderless,
|
|
border_style,
|
|
} => PlacementType::TiledWithOptions(TiledPlacement {
|
|
direction: direction.map(direction_to_proto_i32),
|
|
borderless,
|
|
border_style: border_style.map(|b| b.into()),
|
|
}),
|
|
crate::data::NewPanePlacement::Floating(coords) => {
|
|
PlacementType::Floating(coords.map(|c| c.into()).unwrap_or_default())
|
|
},
|
|
crate::data::NewPanePlacement::InPlace {
|
|
pane_id_to_replace,
|
|
close_replaced_pane,
|
|
borderless,
|
|
border_style,
|
|
} => PlacementType::InPlace(
|
|
crate::client_server_contract::client_server_contract::NewPanePlacementInPlace {
|
|
pane_id_to_replace: pane_id_to_replace.map(|id| id.into()),
|
|
close_replaced_pane,
|
|
borderless,
|
|
border_style: border_style.map(|b| b.into()),
|
|
},
|
|
),
|
|
crate::data::NewPanePlacement::Stacked {
|
|
pane_id_to_stack_under,
|
|
borderless: None,
|
|
border_style: None,
|
|
} => PlacementType::Stacked(
|
|
pane_id_to_stack_under
|
|
.map(|id| id.into())
|
|
.unwrap_or_default(),
|
|
),
|
|
crate::data::NewPanePlacement::Stacked {
|
|
pane_id_to_stack_under,
|
|
borderless,
|
|
border_style,
|
|
} => PlacementType::StackedWithOptions(StackedPlacement {
|
|
pane_id_to_stack_under: pane_id_to_stack_under.map(|id| id.into()),
|
|
borderless,
|
|
border_style: border_style.map(|b| b.into()),
|
|
}),
|
|
};
|
|
Self {
|
|
placement_type: Some(placement_type),
|
|
}
|
|
}
|
|
}
|
|
|
|
// Reverse NewPanePlacement conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::NewPanePlacement>
|
|
for crate::data::NewPanePlacement
|
|
{
|
|
type Error = anyhow::Error;
|
|
fn try_from(
|
|
placement: crate::client_server_contract::client_server_contract::NewPanePlacement,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::new_pane_placement::PlacementType;
|
|
match placement
|
|
.placement_type
|
|
.ok_or_else(|| anyhow!("NewPanePlacement missing placement_type"))?
|
|
{
|
|
// New fields (with borderless support) take priority
|
|
PlacementType::NoPreferenceWithOptions(opts) => {
|
|
Ok(crate::data::NewPanePlacement::NoPreference {
|
|
borderless: opts.borderless,
|
|
border_style: opts.border_style.map(|b| b.into()),
|
|
})
|
|
},
|
|
PlacementType::TiledWithOptions(opts) => {
|
|
let direction = opts.direction.map(proto_i32_to_direction).transpose()?;
|
|
Ok(crate::data::NewPanePlacement::Tiled {
|
|
direction,
|
|
borderless: opts.borderless,
|
|
border_style: opts.border_style.map(|b| b.into()),
|
|
})
|
|
},
|
|
PlacementType::StackedWithOptions(opts) => {
|
|
let pane_id = opts
|
|
.pane_id_to_stack_under
|
|
.map(|id| id.try_into())
|
|
.transpose()?;
|
|
Ok(crate::data::NewPanePlacement::Stacked {
|
|
pane_id_to_stack_under: pane_id,
|
|
borderless: opts.borderless,
|
|
border_style: opts.border_style.map(|b| b.into()),
|
|
})
|
|
},
|
|
// Legacy fields (without borderless support)
|
|
PlacementType::NoPreference(_) => Ok(crate::data::NewPanePlacement::NoPreference {
|
|
borderless: None,
|
|
border_style: None,
|
|
}),
|
|
PlacementType::Tiled(direction) => {
|
|
let direction = if direction == 0 {
|
|
None
|
|
} else {
|
|
Some(proto_i32_to_direction(direction)?)
|
|
};
|
|
Ok(crate::data::NewPanePlacement::Tiled {
|
|
direction,
|
|
borderless: None,
|
|
border_style: None,
|
|
})
|
|
},
|
|
PlacementType::Floating(coords) => {
|
|
let coords = if coords == Default::default() {
|
|
None
|
|
} else {
|
|
Some(coords.try_into()?)
|
|
};
|
|
Ok(crate::data::NewPanePlacement::Floating(coords))
|
|
},
|
|
PlacementType::InPlace(in_place) => Ok(crate::data::NewPanePlacement::InPlace {
|
|
pane_id_to_replace: in_place
|
|
.pane_id_to_replace
|
|
.map(|id| id.try_into())
|
|
.transpose()?,
|
|
close_replaced_pane: in_place.close_replaced_pane,
|
|
borderless: in_place.borderless,
|
|
border_style: in_place.border_style.map(|b| b.into()),
|
|
}),
|
|
PlacementType::Stacked(pane_id) => {
|
|
let pane_id = if pane_id == Default::default() {
|
|
None
|
|
} else {
|
|
Some(pane_id.try_into()?)
|
|
};
|
|
Ok(crate::data::NewPanePlacement::Stacked {
|
|
pane_id_to_stack_under: pane_id,
|
|
borderless: None,
|
|
border_style: None,
|
|
})
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// MouseEvent conversion
|
|
impl From<crate::input::mouse::MouseEvent>
|
|
for crate::client_server_contract::client_server_contract::MouseEvent
|
|
{
|
|
fn from(event: crate::input::mouse::MouseEvent) -> Self {
|
|
use crate::client_server_contract::client_server_contract::{
|
|
MouseEventType as ProtoMouseEventType, Position,
|
|
};
|
|
|
|
let position = Position {
|
|
line: event.position.line.0 as i32,
|
|
column: event.position.column.0 as u64,
|
|
};
|
|
|
|
let event_type = match event.event_type {
|
|
crate::input::mouse::MouseEventType::Press => ProtoMouseEventType::Press as i32,
|
|
crate::input::mouse::MouseEventType::Release => ProtoMouseEventType::Release as i32,
|
|
crate::input::mouse::MouseEventType::Motion => ProtoMouseEventType::Motion as i32,
|
|
};
|
|
|
|
Self {
|
|
event_type,
|
|
left: event.left,
|
|
right: event.right,
|
|
middle: event.middle,
|
|
wheel_up: event.wheel_up,
|
|
wheel_down: event.wheel_down,
|
|
wheel_left: event.wheel_left,
|
|
wheel_right: event.wheel_right,
|
|
shift: event.shift,
|
|
alt: event.alt,
|
|
ctrl: event.ctrl,
|
|
position: Some(position),
|
|
}
|
|
}
|
|
}
|
|
|
|
// RunCommandAction conversion
|
|
impl From<crate::input::command::RunCommandAction>
|
|
for crate::client_server_contract::client_server_contract::RunCommandAction
|
|
{
|
|
fn from(action: crate::input::command::RunCommandAction) -> Self {
|
|
Self {
|
|
command: action.command.to_string_lossy().to_string(),
|
|
args: action.args,
|
|
cwd: action.cwd.map(|p| p.to_string_lossy().to_string()),
|
|
direction: action.direction.map(|d| direction_to_proto_i32(d)),
|
|
hold_on_close: action.hold_on_close,
|
|
hold_on_start: action.hold_on_start,
|
|
originating_plugin: action.originating_plugin.map(|op| op.into()),
|
|
use_terminal_title: action.use_terminal_title,
|
|
}
|
|
}
|
|
}
|
|
|
|
// OriginatingPlugin conversion
|
|
impl From<crate::data::OriginatingPlugin>
|
|
for crate::client_server_contract::client_server_contract::OriginatingPlugin
|
|
{
|
|
fn from(orig: crate::data::OriginatingPlugin) -> Self {
|
|
use std::collections::HashMap;
|
|
let context: HashMap<String, String> =
|
|
orig.context.into_iter().map(|(k, v)| (k, v)).collect();
|
|
|
|
Self {
|
|
plugin_id: orig.plugin_id,
|
|
client_id: orig.client_id as u32,
|
|
context,
|
|
}
|
|
}
|
|
}
|
|
|
|
// OriginatingPlugin reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::OriginatingPlugin>
|
|
for crate::data::OriginatingPlugin
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
orig: crate::client_server_contract::client_server_contract::OriginatingPlugin,
|
|
) -> Result<Self> {
|
|
use std::collections::BTreeMap;
|
|
let context: BTreeMap<String, String> = orig.context.into_iter().collect();
|
|
|
|
Ok(Self {
|
|
plugin_id: orig.plugin_id,
|
|
client_id: orig.client_id as ClientId,
|
|
context,
|
|
})
|
|
}
|
|
}
|
|
|
|
// SplitDirection conversion helper
|
|
fn split_direction_to_proto_i32(direction: crate::input::layout::SplitDirection) -> i32 {
|
|
use crate::client_server_contract::client_server_contract::SplitDirection as ProtoSplitDirection;
|
|
match direction {
|
|
crate::input::layout::SplitDirection::Horizontal => ProtoSplitDirection::Horizontal as i32,
|
|
crate::input::layout::SplitDirection::Vertical => ProtoSplitDirection::Vertical as i32,
|
|
}
|
|
}
|
|
|
|
// SplitSize conversion
|
|
impl From<crate::input::layout::SplitSize>
|
|
for crate::client_server_contract::client_server_contract::SplitSize
|
|
{
|
|
fn from(size: crate::input::layout::SplitSize) -> Self {
|
|
use crate::client_server_contract::client_server_contract::split_size::SizeType;
|
|
match size {
|
|
crate::input::layout::SplitSize::Percent(p) => Self {
|
|
size_type: Some(SizeType::Percent(p as u32)),
|
|
},
|
|
crate::input::layout::SplitSize::Fixed(f) => Self {
|
|
size_type: Some(SizeType::Fixed(f as u32)),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// PercentOrFixed conversion
|
|
impl From<crate::input::layout::PercentOrFixed>
|
|
for crate::client_server_contract::client_server_contract::PercentOrFixed
|
|
{
|
|
fn from(size: crate::input::layout::PercentOrFixed) -> Self {
|
|
use crate::client_server_contract::client_server_contract::percent_or_fixed::SizeType;
|
|
match size {
|
|
crate::input::layout::PercentOrFixed::Percent(p) => Self {
|
|
size_type: Some(SizeType::Percent(p as u32)),
|
|
},
|
|
crate::input::layout::PercentOrFixed::Fixed(f) => Self {
|
|
size_type: Some(SizeType::Fixed(f as u32)),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// Run conversion
|
|
impl From<crate::input::layout::Run>
|
|
for crate::client_server_contract::client_server_contract::Run
|
|
{
|
|
fn from(run: crate::input::layout::Run) -> Self {
|
|
use crate::client_server_contract::client_server_contract::run::RunType;
|
|
match run {
|
|
crate::input::layout::Run::Command(cmd) => Self {
|
|
run_type: Some(RunType::Command(
|
|
crate::client_server_contract::client_server_contract::RunCommandAction {
|
|
command: cmd.command.to_string_lossy().to_string(),
|
|
args: cmd.args,
|
|
cwd: cmd.cwd.map(|p| p.to_string_lossy().to_string()),
|
|
direction: None, // RunCommand doesn't have direction field
|
|
hold_on_close: cmd.hold_on_close,
|
|
hold_on_start: cmd.hold_on_start,
|
|
originating_plugin: cmd.originating_plugin.map(|op| op.into()),
|
|
use_terminal_title: cmd.use_terminal_title,
|
|
},
|
|
)),
|
|
},
|
|
crate::input::layout::Run::Plugin(plugin) => Self {
|
|
run_type: Some(RunType::Plugin(plugin.into())),
|
|
},
|
|
crate::input::layout::Run::EditFile(path, line_number, cwd) => Self {
|
|
run_type: Some(RunType::EditFile(
|
|
crate::client_server_contract::client_server_contract::RunEditFileAction {
|
|
file_path: path.to_string_lossy().to_string(),
|
|
line_number: line_number.map(|n| n as u32),
|
|
cwd: cwd.map(|p| p.to_string_lossy().to_string()),
|
|
},
|
|
)),
|
|
},
|
|
crate::input::layout::Run::Cwd(path) => Self {
|
|
run_type: Some(RunType::Cwd(path.to_string_lossy().to_string())),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// TabLayoutInfo conversion
|
|
impl From<crate::input::layout::TabLayoutInfo>
|
|
for crate::client_server_contract::client_server_contract::TabLayoutInfo
|
|
{
|
|
fn from(tab_info: crate::input::layout::TabLayoutInfo) -> Self {
|
|
Self {
|
|
tab_index: tab_info.tab_index as u32,
|
|
tab_name: tab_info.tab_name,
|
|
tiled_layout: Some(tab_info.tiled_layout.into()),
|
|
floating_layouts: tab_info
|
|
.floating_layouts
|
|
.into_iter()
|
|
.map(|l| l.into())
|
|
.collect(),
|
|
swap_tiled_layouts: tab_info
|
|
.swap_tiled_layouts
|
|
.unwrap_or_default()
|
|
.into_iter()
|
|
.map(|l| l.into())
|
|
.collect(),
|
|
swap_floating_layouts: tab_info
|
|
.swap_floating_layouts
|
|
.unwrap_or_default()
|
|
.into_iter()
|
|
.map(|l| l.into())
|
|
.collect(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::TabLayoutInfo>
|
|
for crate::input::layout::TabLayoutInfo
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
protobuf_tab: crate::client_server_contract::client_server_contract::TabLayoutInfo,
|
|
) -> Result<Self> {
|
|
Ok(crate::input::layout::TabLayoutInfo {
|
|
tab_index: protobuf_tab.tab_index as usize,
|
|
tab_name: protobuf_tab.tab_name.filter(|s| !s.is_empty()),
|
|
tiled_layout: protobuf_tab
|
|
.tiled_layout
|
|
.ok_or_else(|| anyhow!("missing tiled_layout"))?
|
|
.try_into()?,
|
|
floating_layouts: protobuf_tab
|
|
.floating_layouts
|
|
.into_iter()
|
|
.map(|l| l.try_into())
|
|
.collect::<Result<Vec<_>>>()?,
|
|
swap_tiled_layouts: if protobuf_tab.swap_tiled_layouts.is_empty() {
|
|
None
|
|
} else {
|
|
Some(
|
|
protobuf_tab
|
|
.swap_tiled_layouts
|
|
.into_iter()
|
|
.map(|l| l.try_into())
|
|
.collect::<Result<Vec<_>>>()?,
|
|
)
|
|
},
|
|
swap_floating_layouts: if protobuf_tab.swap_floating_layouts.is_empty() {
|
|
None
|
|
} else {
|
|
Some(
|
|
protobuf_tab
|
|
.swap_floating_layouts
|
|
.into_iter()
|
|
.map(|l| l.try_into())
|
|
.collect::<Result<Vec<_>>>()?,
|
|
)
|
|
},
|
|
})
|
|
}
|
|
}
|
|
|
|
// TiledPaneLayout conversion
|
|
impl From<crate::input::layout::TiledPaneLayout>
|
|
for crate::client_server_contract::client_server_contract::TiledPaneLayout
|
|
{
|
|
fn from(layout: crate::input::layout::TiledPaneLayout) -> Self {
|
|
Self {
|
|
children_split_direction: split_direction_to_proto_i32(layout.children_split_direction),
|
|
name: layout.name,
|
|
children: layout.children.into_iter().map(|c| c.into()).collect(),
|
|
split_size: layout.split_size.map(|s| s.into()),
|
|
run: layout.run.map(|r| r.into()),
|
|
borderless: layout.borderless,
|
|
focus: layout.focus.map(|f| f.to_string()),
|
|
exclude_from_sync: layout.exclude_from_sync,
|
|
children_are_stacked: layout.children_are_stacked,
|
|
external_children_index: layout.external_children_index.map(|l| l as u32),
|
|
is_expanded_in_stack: layout.is_expanded_in_stack,
|
|
hide_floating_panes: layout.hide_floating_panes,
|
|
pane_initial_contents: layout.pane_initial_contents,
|
|
default_fg: layout.default_fg,
|
|
default_bg: layout.default_bg,
|
|
border_style: layout.border_style.map(|b| b.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<crate::input::layout::FloatingPaneLayout>
|
|
for crate::client_server_contract::client_server_contract::FloatingPaneLayout
|
|
{
|
|
fn from(layout: crate::input::layout::FloatingPaneLayout) -> Self {
|
|
Self {
|
|
name: layout.name,
|
|
height: layout.height.map(|h| h.into()),
|
|
width: layout.width.map(|w| w.into()),
|
|
x: layout.x.map(|x| x.into()),
|
|
y: layout.y.map(|y| y.into()),
|
|
pinned: layout.pinned,
|
|
run: layout.run.map(|r| r.into()),
|
|
focus: layout.focus,
|
|
already_running: layout.already_running,
|
|
pane_initial_contents: layout.pane_initial_contents,
|
|
logical_position: layout.logical_position.map(|l| l as u32),
|
|
borderless: layout.borderless,
|
|
default_fg: layout.default_fg,
|
|
default_bg: layout.default_bg,
|
|
border_style: layout.border_style.map(|b| b.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<crate::input::layout::SwapTiledLayout>
|
|
for crate::client_server_contract::client_server_contract::SwapTiledLayout
|
|
{
|
|
fn from(layout: crate::input::layout::SwapTiledLayout) -> Self {
|
|
use crate::client_server_contract::client_server_contract::LayoutConstraintTiledPair;
|
|
|
|
let constraint_map = layout
|
|
.0
|
|
.into_iter()
|
|
.map(|(constraint, tiled_layout)| LayoutConstraintTiledPair {
|
|
constraint: Some(constraint.into()),
|
|
layout: Some(tiled_layout.into()),
|
|
})
|
|
.collect();
|
|
|
|
Self {
|
|
constraint_map,
|
|
name: layout.1,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<crate::input::layout::SwapFloatingLayout>
|
|
for crate::client_server_contract::client_server_contract::SwapFloatingLayout
|
|
{
|
|
fn from(layout: crate::input::layout::SwapFloatingLayout) -> Self {
|
|
use crate::client_server_contract::client_server_contract::LayoutConstraintFloatingPair;
|
|
|
|
let constraint_map = layout
|
|
.0
|
|
.into_iter()
|
|
.map(
|
|
|(constraint, floating_layouts)| LayoutConstraintFloatingPair {
|
|
constraint: Some(constraint.into()),
|
|
layouts: floating_layouts.into_iter().map(|l| l.into()).collect(),
|
|
},
|
|
)
|
|
.collect();
|
|
|
|
Self {
|
|
constraint_map,
|
|
name: layout.1,
|
|
}
|
|
}
|
|
}
|
|
|
|
// PluginUserConfiguration conversion
|
|
impl From<crate::input::layout::PluginUserConfiguration>
|
|
for crate::client_server_contract::client_server_contract::PluginUserConfiguration
|
|
{
|
|
fn from(config: crate::input::layout::PluginUserConfiguration) -> Self {
|
|
Self {
|
|
configuration: config.inner().clone().into_iter().collect(), // Convert BTreeMap to HashMap
|
|
}
|
|
}
|
|
}
|
|
|
|
// LayoutConstraint conversion
|
|
impl From<crate::input::layout::LayoutConstraint>
|
|
for crate::client_server_contract::client_server_contract::LayoutConstraintWithValue
|
|
{
|
|
fn from(constraint: crate::input::layout::LayoutConstraint) -> Self {
|
|
use crate::client_server_contract::client_server_contract::LayoutConstraint as ProtoLayoutConstraint;
|
|
match constraint {
|
|
crate::input::layout::LayoutConstraint::MaxPanes(n) => Self {
|
|
constraint_type: ProtoLayoutConstraint::MaxPanes as i32,
|
|
value: Some(n as u32),
|
|
},
|
|
crate::input::layout::LayoutConstraint::MinPanes(n) => Self {
|
|
constraint_type: ProtoLayoutConstraint::MinPanes as i32,
|
|
value: Some(n as u32),
|
|
},
|
|
crate::input::layout::LayoutConstraint::ExactPanes(n) => Self {
|
|
constraint_type: ProtoLayoutConstraint::ExactPanes as i32,
|
|
value: Some(n as u32),
|
|
},
|
|
crate::input::layout::LayoutConstraint::NoConstraint => Self {
|
|
constraint_type: ProtoLayoutConstraint::NoConstraint as i32,
|
|
value: None,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// RunPlugin conversion
|
|
impl From<crate::input::layout::RunPlugin>
|
|
for crate::client_server_contract::client_server_contract::RunPlugin
|
|
{
|
|
fn from(plugin: crate::input::layout::RunPlugin) -> Self {
|
|
Self {
|
|
allow_exec_host_cmd: plugin._allow_exec_host_cmd,
|
|
location: Some(plugin.location.into()),
|
|
configuration: Some(plugin.configuration.into()),
|
|
initial_cwd: plugin.initial_cwd.map(|p| p.display().to_string()),
|
|
}
|
|
}
|
|
}
|
|
|
|
// PluginAlias conversion
|
|
impl From<crate::input::layout::PluginAlias>
|
|
for crate::client_server_contract::client_server_contract::PluginAlias
|
|
{
|
|
fn from(plugin: crate::input::layout::PluginAlias) -> Self {
|
|
Self {
|
|
name: plugin.name,
|
|
configuration: plugin.configuration.map(|c| c.into()),
|
|
initial_cwd: plugin.initial_cwd.map(|i| i.display().to_string()),
|
|
run_plugin: plugin.run_plugin.map(|r| r.into()),
|
|
}
|
|
}
|
|
}
|
|
|
|
// RunPluginLocation conversion
|
|
impl From<crate::input::layout::RunPluginLocation>
|
|
for crate::client_server_contract::client_server_contract::RunPluginLocationData
|
|
{
|
|
fn from(location: crate::input::layout::RunPluginLocation) -> Self {
|
|
use crate::client_server_contract::client_server_contract::{
|
|
run_plugin_location_data::LocationData, RunPluginLocation as ProtoRunPluginLocation,
|
|
};
|
|
match location {
|
|
crate::input::layout::RunPluginLocation::File(path) => Self {
|
|
location_type: ProtoRunPluginLocation::File as i32,
|
|
location_data: Some(LocationData::FilePath(path.to_string_lossy().to_string())),
|
|
},
|
|
crate::input::layout::RunPluginLocation::Zellij(tag) => Self {
|
|
location_type: ProtoRunPluginLocation::Zellij as i32,
|
|
location_data: Some(LocationData::ZellijTag(
|
|
crate::client_server_contract::client_server_contract::PluginTag {
|
|
tag: tag.to_string(),
|
|
},
|
|
)),
|
|
},
|
|
crate::input::layout::RunPluginLocation::Remote(url) => Self {
|
|
location_type: ProtoRunPluginLocation::Remote as i32,
|
|
location_data: Some(LocationData::RemoteUrl(url)),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// RunPluginOrAlias conversion
|
|
impl From<crate::input::layout::RunPluginOrAlias>
|
|
for crate::client_server_contract::client_server_contract::RunPluginOrAlias
|
|
{
|
|
fn from(plugin: crate::input::layout::RunPluginOrAlias) -> Self {
|
|
use crate::client_server_contract::client_server_contract::run_plugin_or_alias::PluginType;
|
|
match plugin {
|
|
crate::input::layout::RunPluginOrAlias::RunPlugin(run_plugin) => Self {
|
|
plugin_type: Some(PluginType::Plugin(run_plugin.into())),
|
|
},
|
|
crate::input::layout::RunPluginOrAlias::Alias(alias) => Self {
|
|
plugin_type: Some(PluginType::Alias(alias.into())),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// CommandOrPlugin conversion
|
|
impl From<crate::data::CommandOrPlugin>
|
|
for crate::client_server_contract::client_server_contract::CommandOrPlugin
|
|
{
|
|
fn from(cmd_or_plugin: crate::data::CommandOrPlugin) -> Self {
|
|
use crate::client_server_contract::client_server_contract::command_or_plugin::CommandOrPluginType;
|
|
use crate::client_server_contract::client_server_contract::CommandOrPluginFile;
|
|
match cmd_or_plugin {
|
|
crate::data::CommandOrPlugin::Command(cmd) => Self {
|
|
command_or_plugin_type: Some(CommandOrPluginType::Command(cmd.into())),
|
|
},
|
|
crate::data::CommandOrPlugin::Plugin(plugin) => Self {
|
|
command_or_plugin_type: Some(CommandOrPluginType::Plugin(plugin.into())),
|
|
},
|
|
crate::data::CommandOrPlugin::File(f) => Self {
|
|
command_or_plugin_type: Some(CommandOrPluginType::File(CommandOrPluginFile {
|
|
path: f.path.display().to_string(),
|
|
line_number: f.line_number.map(|n| n as i32),
|
|
cwd: f.cwd.map(|c| c.display().to_string()),
|
|
})),
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::CommandOrPlugin>
|
|
for crate::data::CommandOrPlugin
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
proto: crate::client_server_contract::client_server_contract::CommandOrPlugin,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::command_or_plugin::CommandOrPluginType;
|
|
|
|
let cmd_or_plugin_type = proto
|
|
.command_or_plugin_type
|
|
.ok_or_else(|| anyhow!("CommandOrPlugin missing command_or_plugin_type"))?;
|
|
match cmd_or_plugin_type {
|
|
CommandOrPluginType::Command(cmd) => {
|
|
Ok(crate::data::CommandOrPlugin::Command(cmd.try_into()?))
|
|
},
|
|
CommandOrPluginType::Plugin(plugin) => {
|
|
Ok(crate::data::CommandOrPlugin::Plugin(plugin.try_into()?))
|
|
},
|
|
CommandOrPluginType::File(f) => Ok(crate::data::CommandOrPlugin::File(
|
|
crate::data::FileToOpen {
|
|
path: std::path::PathBuf::from(&f.path),
|
|
line_number: f.line_number.map(|n| n as usize),
|
|
cwd: f.cwd.map(std::path::PathBuf::from),
|
|
border_style: None,
|
|
},
|
|
)),
|
|
}
|
|
}
|
|
}
|
|
|
|
// Run reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::Run>
|
|
for crate::input::layout::Run
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(run: crate::client_server_contract::client_server_contract::Run) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::run::RunType;
|
|
|
|
let run_type = run
|
|
.run_type
|
|
.ok_or_else(|| anyhow!("Run missing run_type"))?;
|
|
match run_type {
|
|
RunType::Command(cmd) => Ok(crate::input::layout::Run::Command(
|
|
crate::input::command::RunCommand {
|
|
command: std::path::PathBuf::from(cmd.command),
|
|
args: cmd.args,
|
|
cwd: cmd.cwd.map(std::path::PathBuf::from),
|
|
hold_on_close: cmd.hold_on_close,
|
|
hold_on_start: cmd.hold_on_start,
|
|
originating_plugin: cmd
|
|
.originating_plugin
|
|
.map(|op| op.try_into())
|
|
.transpose()?,
|
|
use_terminal_title: cmd.use_terminal_title,
|
|
},
|
|
)),
|
|
RunType::EditFile(edit) => Ok(crate::input::layout::Run::EditFile(
|
|
std::path::PathBuf::from(edit.file_path),
|
|
edit.line_number.map(|n| n as usize),
|
|
edit.cwd.map(std::path::PathBuf::from),
|
|
)),
|
|
RunType::Cwd(cwd_str) => Ok(crate::input::layout::Run::Cwd(std::path::PathBuf::from(
|
|
cwd_str,
|
|
))),
|
|
RunType::Plugin(plugin) => Ok(crate::input::layout::Run::Plugin(plugin.try_into()?)),
|
|
}
|
|
}
|
|
}
|
|
|
|
// PercentOrFixed reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::PercentOrFixed>
|
|
for crate::input::layout::PercentOrFixed
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
value: crate::client_server_contract::client_server_contract::PercentOrFixed,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::percent_or_fixed::SizeType;
|
|
|
|
let size_type = value
|
|
.size_type
|
|
.ok_or_else(|| anyhow!("PercentOrFixed missing size_type"))?;
|
|
match size_type {
|
|
SizeType::Percent(percent) => Ok(crate::input::layout::PercentOrFixed::Percent(
|
|
percent as usize,
|
|
)),
|
|
SizeType::Fixed(fixed) => {
|
|
Ok(crate::input::layout::PercentOrFixed::Fixed(fixed as usize))
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
// ===== REVERSE CONVERSIONS =====
|
|
|
|
// MouseEvent reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::MouseEvent>
|
|
for crate::input::mouse::MouseEvent
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
event: crate::client_server_contract::client_server_contract::MouseEvent,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::MouseEventType as ProtoMouseEventType;
|
|
|
|
let event_type = match event.event_type {
|
|
x if x == ProtoMouseEventType::Press as i32 => {
|
|
crate::input::mouse::MouseEventType::Press
|
|
},
|
|
x if x == ProtoMouseEventType::Release as i32 => {
|
|
crate::input::mouse::MouseEventType::Release
|
|
},
|
|
x if x == ProtoMouseEventType::Motion as i32 => {
|
|
crate::input::mouse::MouseEventType::Motion
|
|
},
|
|
_ => return Err(anyhow!("Invalid MouseEventType: {}", event.event_type)),
|
|
};
|
|
|
|
let position = event
|
|
.position
|
|
.ok_or_else(|| anyhow!("MouseEvent missing position"))?
|
|
.try_into()?;
|
|
|
|
Ok(crate::input::mouse::MouseEvent {
|
|
event_type,
|
|
left: event.left,
|
|
right: event.right,
|
|
middle: event.middle,
|
|
wheel_up: event.wheel_up,
|
|
wheel_down: event.wheel_down,
|
|
wheel_left: event.wheel_left,
|
|
wheel_right: event.wheel_right,
|
|
shift: event.shift,
|
|
alt: event.alt,
|
|
ctrl: event.ctrl,
|
|
position,
|
|
})
|
|
}
|
|
}
|
|
|
|
// RunCommandAction reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::RunCommandAction>
|
|
for crate::input::command::RunCommandAction
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
action: crate::client_server_contract::client_server_contract::RunCommandAction,
|
|
) -> Result<Self> {
|
|
Ok(crate::input::command::RunCommandAction {
|
|
command: std::path::PathBuf::from(action.command),
|
|
args: action.args,
|
|
cwd: action.cwd.map(std::path::PathBuf::from),
|
|
direction: action.direction.map(proto_i32_to_direction).transpose()?,
|
|
hold_on_close: action.hold_on_close,
|
|
hold_on_start: action.hold_on_start,
|
|
originating_plugin: action
|
|
.originating_plugin
|
|
.map(|op| op.try_into())
|
|
.transpose()?,
|
|
use_terminal_title: action.use_terminal_title,
|
|
})
|
|
}
|
|
}
|
|
|
|
// TiledPaneLayout reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::TiledPaneLayout>
|
|
for crate::input::layout::TiledPaneLayout
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
layout: crate::client_server_contract::client_server_contract::TiledPaneLayout,
|
|
) -> Result<Self> {
|
|
use crate::input::layout::{SplitDirection, SplitSize, TiledPaneLayout};
|
|
|
|
let children_split_direction = match layout.children_split_direction {
|
|
x if x
|
|
== crate::client_server_contract::client_server_contract::SplitDirection::Horizontal
|
|
as i32 =>
|
|
{
|
|
SplitDirection::Horizontal
|
|
},
|
|
x if x
|
|
== crate::client_server_contract::client_server_contract::SplitDirection::Vertical
|
|
as i32 =>
|
|
{
|
|
SplitDirection::Vertical
|
|
},
|
|
_ => SplitDirection::Horizontal, // default
|
|
};
|
|
|
|
let children: Result<Vec<_>> = layout.children.into_iter().map(|c| c.try_into()).collect();
|
|
let run = layout.run.map(|r| r.try_into()).transpose()?;
|
|
|
|
let split_size = layout.split_size.and_then(|size| {
|
|
use crate::client_server_contract::client_server_contract::split_size::SizeType;
|
|
match size.size_type {
|
|
Some(SizeType::Percent(percent)) => Some(SplitSize::Percent(percent as usize)),
|
|
Some(SizeType::Fixed(fixed)) => Some(SplitSize::Fixed(fixed as usize)),
|
|
None => None,
|
|
}
|
|
});
|
|
|
|
Ok(TiledPaneLayout {
|
|
children_split_direction,
|
|
name: layout.name,
|
|
children: children?,
|
|
split_size,
|
|
run,
|
|
borderless: layout.borderless,
|
|
focus: layout.focus.map(|f| f == "true"), // Convert string to bool
|
|
external_children_index: layout.external_children_index.map(|l| l as usize),
|
|
children_are_stacked: layout.children_are_stacked,
|
|
is_expanded_in_stack: layout.is_expanded_in_stack,
|
|
exclude_from_sync: layout.exclude_from_sync,
|
|
run_instructions_to_ignore: vec![], // not represented in protobuf
|
|
hide_floating_panes: layout.hide_floating_panes,
|
|
pane_initial_contents: layout.pane_initial_contents,
|
|
default_fg: layout.default_fg,
|
|
default_bg: layout.default_bg,
|
|
border_style: layout.border_style.map(|b| b.into()),
|
|
})
|
|
}
|
|
}
|
|
|
|
// FloatingPaneLayout reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::FloatingPaneLayout>
|
|
for crate::input::layout::FloatingPaneLayout
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
layout: crate::client_server_contract::client_server_contract::FloatingPaneLayout,
|
|
) -> Result<Self> {
|
|
let run = layout.run.map(|r| r.try_into()).transpose()?;
|
|
let height = layout.height.map(|h| h.try_into()).transpose()?;
|
|
let width = layout.width.map(|w| w.try_into()).transpose()?;
|
|
let x = layout.x.map(|x| x.try_into()).transpose()?;
|
|
let y = layout.y.map(|y| y.try_into()).transpose()?;
|
|
|
|
Ok(crate::input::layout::FloatingPaneLayout {
|
|
name: layout.name,
|
|
height,
|
|
width,
|
|
x,
|
|
y,
|
|
pinned: layout.pinned,
|
|
run,
|
|
focus: layout.focus,
|
|
already_running: layout.already_running,
|
|
pane_initial_contents: layout.pane_initial_contents,
|
|
logical_position: layout.logical_position.map(|p| p as usize),
|
|
borderless: layout.borderless,
|
|
default_fg: layout.default_fg,
|
|
default_bg: layout.default_bg,
|
|
border_style: layout.border_style.map(|b| b.into()),
|
|
})
|
|
}
|
|
}
|
|
|
|
// SwapTiledLayout reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::SwapTiledLayout>
|
|
for crate::input::layout::SwapTiledLayout
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
layout: crate::client_server_contract::client_server_contract::SwapTiledLayout,
|
|
) -> Result<Self> {
|
|
let constraint_map: Result<BTreeMap<_, _>> = layout
|
|
.constraint_map
|
|
.into_iter()
|
|
.map(|pair| {
|
|
Ok((
|
|
pair.constraint
|
|
.ok_or_else(|| anyhow!("Missing constraint"))?
|
|
.try_into()?,
|
|
pair.layout
|
|
.ok_or_else(|| anyhow!("Missing layout"))?
|
|
.try_into()?,
|
|
))
|
|
})
|
|
.collect();
|
|
Ok((constraint_map?, layout.name))
|
|
}
|
|
}
|
|
|
|
// SwapFloatingLayout reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::SwapFloatingLayout>
|
|
for crate::input::layout::SwapFloatingLayout
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
layout: crate::client_server_contract::client_server_contract::SwapFloatingLayout,
|
|
) -> Result<Self> {
|
|
let constraint_map: Result<BTreeMap<_, _>> = layout
|
|
.constraint_map
|
|
.into_iter()
|
|
.map(|pair| {
|
|
let floating_layouts: Result<Vec<_>> =
|
|
pair.layouts.into_iter().map(|l| l.try_into()).collect();
|
|
Ok((
|
|
pair.constraint
|
|
.ok_or_else(|| anyhow!("Missing constraint"))?
|
|
.try_into()?,
|
|
floating_layouts?,
|
|
))
|
|
})
|
|
.collect();
|
|
|
|
Ok((constraint_map?, layout.name))
|
|
}
|
|
}
|
|
|
|
// PluginUserConfiguration reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::PluginUserConfiguration>
|
|
for crate::input::layout::PluginUserConfiguration
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
config: crate::client_server_contract::client_server_contract::PluginUserConfiguration,
|
|
) -> Result<Self> {
|
|
let btree_map: BTreeMap<String, String> = config.configuration.into_iter().collect();
|
|
Ok(crate::input::layout::PluginUserConfiguration::new(
|
|
btree_map,
|
|
))
|
|
}
|
|
}
|
|
|
|
// LayoutConstraint reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::LayoutConstraintWithValue>
|
|
for crate::input::layout::LayoutConstraint
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
constraint: crate::client_server_contract::client_server_contract::LayoutConstraintWithValue,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::LayoutConstraint as ProtoLayoutConstraint;
|
|
match constraint.constraint_type {
|
|
x if x == ProtoLayoutConstraint::MaxPanes as i32 => {
|
|
let value = constraint
|
|
.value
|
|
.ok_or_else(|| anyhow!("MaxPanes constraint missing value"))?
|
|
as usize;
|
|
Ok(crate::input::layout::LayoutConstraint::MaxPanes(value))
|
|
},
|
|
x if x == ProtoLayoutConstraint::MinPanes as i32 => {
|
|
let value = constraint
|
|
.value
|
|
.ok_or_else(|| anyhow!("MinPanes constraint missing value"))?
|
|
as usize;
|
|
Ok(crate::input::layout::LayoutConstraint::MinPanes(value))
|
|
},
|
|
x if x == ProtoLayoutConstraint::ExactPanes as i32 => {
|
|
let value = constraint
|
|
.value
|
|
.ok_or_else(|| anyhow!("ExactPanes constraint missing value"))?
|
|
as usize;
|
|
Ok(crate::input::layout::LayoutConstraint::ExactPanes(value))
|
|
},
|
|
x if x == ProtoLayoutConstraint::NoConstraint as i32 => {
|
|
Ok(crate::input::layout::LayoutConstraint::NoConstraint)
|
|
},
|
|
_ => Err(anyhow!(
|
|
"Invalid LayoutConstraint type: {}",
|
|
constraint.constraint_type
|
|
)),
|
|
}
|
|
}
|
|
}
|
|
|
|
// RunPlugin reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::RunPlugin>
|
|
for crate::input::layout::RunPlugin
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
plugin: crate::client_server_contract::client_server_contract::RunPlugin,
|
|
) -> Result<Self> {
|
|
let location = plugin
|
|
.location
|
|
.ok_or_else(|| anyhow!("RunPlugin missing location"))?
|
|
.try_into()?;
|
|
let configuration = plugin
|
|
.configuration
|
|
.ok_or_else(|| anyhow!("RunPlugin missing configuration"))?
|
|
.try_into()?;
|
|
let initial_cwd = plugin.initial_cwd.map(std::path::PathBuf::from);
|
|
|
|
Ok(crate::input::layout::RunPlugin {
|
|
_allow_exec_host_cmd: plugin.allow_exec_host_cmd,
|
|
location,
|
|
configuration,
|
|
initial_cwd,
|
|
})
|
|
}
|
|
}
|
|
|
|
// PluginAlias reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::PluginAlias>
|
|
for crate::input::layout::PluginAlias
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
plugin_alias: crate::client_server_contract::client_server_contract::PluginAlias,
|
|
) -> Result<Self> {
|
|
let run_plugin = plugin_alias.run_plugin.and_then(|r| r.try_into().ok());
|
|
let configuration = plugin_alias.configuration.and_then(|c| c.try_into().ok());
|
|
let initial_cwd = plugin_alias.initial_cwd.map(std::path::PathBuf::from);
|
|
Ok(crate::input::layout::PluginAlias {
|
|
name: plugin_alias.name,
|
|
configuration,
|
|
initial_cwd,
|
|
run_plugin,
|
|
})
|
|
}
|
|
}
|
|
|
|
// RunPluginLocation reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::RunPluginLocationData>
|
|
for crate::input::layout::RunPluginLocation
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
location: crate::client_server_contract::client_server_contract::RunPluginLocationData,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::{
|
|
run_plugin_location_data::LocationData, RunPluginLocation as ProtoRunPluginLocation,
|
|
};
|
|
|
|
let location_data = location
|
|
.location_data
|
|
.ok_or_else(|| anyhow!("RunPluginLocationData missing location_data"))?;
|
|
match location.location_type {
|
|
x if x == ProtoRunPluginLocation::File as i32 => {
|
|
if let LocationData::FilePath(path) = location_data {
|
|
Ok(crate::input::layout::RunPluginLocation::File(
|
|
std::path::PathBuf::from(path),
|
|
))
|
|
} else {
|
|
Err(anyhow!("File location type but wrong data variant"))
|
|
}
|
|
},
|
|
x if x == ProtoRunPluginLocation::Zellij as i32 => {
|
|
if let LocationData::ZellijTag(tag) = location_data {
|
|
Ok(crate::input::layout::RunPluginLocation::Zellij(
|
|
crate::data::PluginTag::new(tag.tag),
|
|
))
|
|
} else {
|
|
Err(anyhow!("Zellij location type but wrong data variant"))
|
|
}
|
|
},
|
|
x if x == ProtoRunPluginLocation::Remote as i32 => {
|
|
if let LocationData::RemoteUrl(url) = location_data {
|
|
Ok(crate::input::layout::RunPluginLocation::Remote(url))
|
|
} else {
|
|
Err(anyhow!("Remote location type but wrong data variant"))
|
|
}
|
|
},
|
|
_ => Err(anyhow!(
|
|
"Invalid RunPluginLocation type: {}",
|
|
location.location_type
|
|
)),
|
|
}
|
|
}
|
|
}
|
|
|
|
// RunPluginOrAlias reverse conversion
|
|
impl TryFrom<crate::client_server_contract::client_server_contract::RunPluginOrAlias>
|
|
for crate::input::layout::RunPluginOrAlias
|
|
{
|
|
type Error = anyhow::Error;
|
|
|
|
fn try_from(
|
|
plugin: crate::client_server_contract::client_server_contract::RunPluginOrAlias,
|
|
) -> Result<Self> {
|
|
use crate::client_server_contract::client_server_contract::run_plugin_or_alias::PluginType;
|
|
|
|
let plugin_type = plugin
|
|
.plugin_type
|
|
.ok_or_else(|| anyhow!("RunPluginOrAlias missing plugin_type"))?;
|
|
match plugin_type {
|
|
PluginType::Plugin(run_plugin) => Ok(
|
|
crate::input::layout::RunPluginOrAlias::RunPlugin(run_plugin.try_into()?),
|
|
),
|
|
PluginType::Alias(plugin_alias) => Ok(crate::input::layout::RunPluginOrAlias::Alias(
|
|
plugin_alias.try_into()?,
|
|
)),
|
|
}
|
|
}
|
|
}
|