feat(plugins): send info about $EDITOR and $SHELL (#3971)

* feat(plugins): send info about $EDITOR and $SHELL

* fix(e2e): snapshot update
This commit is contained in:
Aram Drevekenin 2025-02-02 16:19:15 +01:00 committed by GitHub
parent 1dd685062d
commit 3267d36589
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 113 additions and 26 deletions

View file

@ -364,6 +364,7 @@ impl SessionMetaData {
rounded_corners: new_config.ui.pane_frames.rounded_corners,
hide_session_name: new_config.ui.pane_frames.hide_session_name,
stacked_resize: new_config.options.stacked_resize.unwrap_or(true),
default_editor: new_config.options.scrollback_editor.clone(),
})
.unwrap();
self.senders

View file

@ -1,6 +1,6 @@
---
source: zellij-server/src/plugins/./unit/plugin_tests.rs
assertion_line: 1043
assertion_line: 1143
expression: "format!(\"{:#?}\", switch_to_mode_event)"
---
Some(
@ -76,6 +76,8 @@ Some(
session_name: Some(
"zellij-test",
),
editor: None,
shell: None,
},
1,
),

View file

@ -40,7 +40,7 @@ use crate::{
panes::sixel::SixelImageStore,
panes::PaneId,
plugins::{PluginId, PluginInstruction, PluginRenderAsset},
pty::{ClientTabIndexOrPaneId, PtyInstruction, VteBytes},
pty::{get_default_shell, ClientTabIndexOrPaneId, PtyInstruction, VteBytes},
tab::{SuppressedPanes, Tab},
thread_bus::Bus,
ui::{
@ -368,6 +368,7 @@ pub enum ScreenInstruction {
rounded_corners: bool,
hide_session_name: bool,
stacked_resize: bool,
default_editor: Option<PathBuf>,
},
RerunCommandPane(u32), // u32 - terminal pane id
ResizePaneWithId(ResizeStrategy, PaneId),
@ -687,12 +688,13 @@ pub(crate) struct Screen {
resurrectable_sessions: BTreeMap<String, Duration>, // String is the session name, duration is
// its creation time
default_layout: Box<Layout>,
default_shell: Option<PathBuf>,
default_shell: PathBuf,
styled_underlines: bool,
arrow_fonts: bool,
layout_dir: Option<PathBuf>,
default_layout_name: Option<String>,
explicitly_disable_kitty_keyboard_protocol: bool,
default_editor: Option<PathBuf>,
}
impl Screen {
@ -709,7 +711,7 @@ impl Screen {
debug: bool,
default_layout: Box<Layout>,
default_layout_name: Option<String>,
default_shell: Option<PathBuf>,
default_shell: PathBuf,
session_serialization: bool,
serialize_pane_viewport: bool,
scrollback_lines_to_serialize: Option<usize>,
@ -718,6 +720,7 @@ impl Screen {
layout_dir: Option<PathBuf>,
explicitly_disable_kitty_keyboard_protocol: bool,
stacked_resize: bool,
default_editor: Option<PathBuf>,
) -> Self {
let session_name = mode_info.session_name.clone().unwrap_or_default();
let session_info = SessionInfo::new(session_name.clone());
@ -760,6 +763,7 @@ impl Screen {
resurrectable_sessions,
layout_dir,
explicitly_disable_kitty_keyboard_protocol,
default_editor,
}
}
@ -1359,6 +1363,7 @@ impl Screen {
self.arrow_fonts,
self.styled_underlines,
self.explicitly_disable_kitty_keyboard_protocol,
self.default_editor.clone(),
);
for (client_id, mode_info) in &self.mode_info {
tab.change_mode_info(mode_info.clone(), *client_id);
@ -1650,7 +1655,7 @@ impl Screen {
}
fn dump_layout_to_hd(&mut self) -> Result<()> {
let err_context = || format!("Failed to log and report session state");
let session_layout_metadata = self.get_layout_metadata(self.default_shell.clone());
let session_layout_metadata = self.get_layout_metadata(Some(self.default_shell.clone()));
self.bus
.senders
.send_to_plugin(PluginInstruction::LogLayoutToHd(session_layout_metadata))
@ -2450,6 +2455,7 @@ impl Screen {
rounded_corners: bool,
hide_session_name: bool,
stacked_resize: bool,
default_editor: Option<PathBuf>,
client_id: ClientId,
) -> Result<()> {
let should_support_arrow_fonts = !simplified_ui;
@ -2458,7 +2464,8 @@ impl Screen {
self.default_mode_info.update_theme(theme);
self.default_mode_info
.update_rounded_corners(rounded_corners);
self.default_shell = default_shell.clone();
self.default_shell = default_shell.clone().unwrap_or_else(|| get_default_shell());
self.default_editor = default_editor.clone().or_else(|| get_default_editor());
self.auto_layout = auto_layout;
self.copy_options.command = copy_command.clone();
self.copy_options.copy_on_select = copy_on_select;
@ -2477,6 +2484,7 @@ impl Screen {
tab.update_theme(theme);
tab.update_rounded_corners(rounded_corners);
tab.update_default_shell(default_shell.clone());
tab.update_default_editor(self.default_editor.clone());
tab.update_auto_layout(auto_layout);
tab.update_copy_options(&self.copy_options);
tab.set_pane_frames(pane_frames);
@ -2749,6 +2757,19 @@ impl Screen {
}
}
#[cfg(not(test))]
fn get_default_editor() -> Option<PathBuf> {
std::env::var("EDITOR")
.or_else(|_| std::env::var("VISUAL"))
.map(|e| PathBuf::from(e))
.ok()
}
#[cfg(test)]
fn get_default_editor() -> Option<PathBuf> {
None
}
// The box is here in order to make the
// NewClient enum smaller
#[allow(clippy::boxed_local)]
@ -2769,7 +2790,20 @@ pub(crate) fn screen_thread_main(
let scrollback_lines_to_serialize = config_options.scrollback_lines_to_serialize;
let session_is_mirrored = config_options.mirror_session.unwrap_or(false);
let layout_dir = config_options.layout_dir;
let default_shell = config_options.default_shell;
#[cfg(test)]
let default_shell = config_options
.default_shell
.clone()
.unwrap_or(PathBuf::from("/bin/sh"));
#[cfg(not(test))]
let default_shell = config_options
.default_shell
.clone()
.unwrap_or_else(|| get_default_shell());
let default_editor = config_options
.scrollback_editor
.clone()
.or_else(|| get_default_editor());
let default_layout_name = config_options
.default_layout
.map(|l| format!("{}", l.display()));
@ -2819,6 +2853,7 @@ pub(crate) fn screen_thread_main(
layout_dir,
explicitly_disable_kitty_keyboard_protocol,
stacked_resize,
default_editor,
);
let mut pending_tab_ids: HashSet<usize> = HashSet::new();
@ -3240,7 +3275,7 @@ pub(crate) fn screen_thread_main(
ScreenInstruction::DumpLayoutToPlugin(plugin_id) => {
let err_context = || format!("Failed to dump layout");
let session_layout_metadata =
screen.get_layout_metadata(screen.default_shell.clone());
screen.get_layout_metadata(Some(screen.default_shell.clone()));
screen
.bus
.senders
@ -3254,7 +3289,7 @@ pub(crate) fn screen_thread_main(
ScreenInstruction::ListClientsToPlugin(plugin_id, client_id) => {
let err_context = || format!("Failed to dump layout");
let session_layout_metadata =
screen.get_layout_metadata(screen.default_shell.clone());
screen.get_layout_metadata(Some(screen.default_shell.clone()));
screen
.bus
.senders
@ -4561,6 +4596,7 @@ pub(crate) fn screen_thread_main(
rounded_corners,
hide_session_name,
stacked_resize,
default_editor,
} => {
screen
.reconfigure(
@ -4577,6 +4613,7 @@ pub(crate) fn screen_thread_main(
rounded_corners,
hide_session_name,
stacked_resize,
default_editor,
client_id,
)
.non_fatal();

View file

@ -188,7 +188,8 @@ pub(crate) struct Tab {
pending_instructions: Vec<BufferedTabInstruction>, // instructions that came while the tab was
// pending and need to be re-applied
swap_layouts: SwapLayouts,
default_shell: Option<PathBuf>,
default_shell: PathBuf,
default_editor: Option<PathBuf>,
debug: bool,
arrow_fonts: bool,
styled_underlines: bool,
@ -582,11 +583,12 @@ impl Tab {
terminal_emulator_colors: Rc<RefCell<Palette>>,
terminal_emulator_color_codes: Rc<RefCell<HashMap<usize, String>>>,
swap_layouts: (Vec<SwapTiledLayout>, Vec<SwapFloatingLayout>),
default_shell: Option<PathBuf>,
default_shell: PathBuf,
debug: bool,
arrow_fonts: bool,
styled_underlines: bool,
explicitly_disable_kitty_keyboard_protocol: bool,
default_editor: Option<PathBuf>,
) -> Self {
let name = if name.is_empty() {
format!("Tab #{}", index + 1)
@ -682,6 +684,7 @@ impl Tab {
arrow_fonts,
styled_underlines,
explicitly_disable_kitty_keyboard_protocol,
default_editor,
}
}
@ -886,8 +889,13 @@ impl Tab {
let mode_infos = self.mode_info.borrow();
let mut plugin_updates = vec![];
for client_id in self.connected_clients.borrow().iter() {
let mode_info = mode_infos.get(client_id).unwrap_or(&self.default_mode_info);
plugin_updates.push((None, Some(*client_id), Event::ModeUpdate(mode_info.clone())));
let mut mode_info = mode_infos
.get(client_id)
.unwrap_or(&self.default_mode_info)
.clone();
mode_info.shell = Some(self.default_shell.clone());
mode_info.editor = self.default_editor.clone();
plugin_updates.push((None, Some(*client_id), Event::ModeUpdate(mode_info)));
}
self.senders
.send_to_plugin(PluginInstruction::Update(plugin_updates))
@ -1906,7 +1914,7 @@ impl Tab {
self.senders
.send_to_pty(PtyInstruction::DropToShellInPane {
pane_id: PaneId::Terminal(active_terminal_id),
shell: self.default_shell.clone(),
shell: Some(self.default_shell.clone()),
working_dir,
})
.with_context(err_context)?;
@ -4418,8 +4426,15 @@ impl Tab {
pane.update_arrow_fonts(should_support_arrow_fonts);
}
}
pub fn update_default_shell(&mut self, default_shell: Option<PathBuf>) {
self.default_shell = default_shell;
pub fn update_default_shell(&mut self, mut default_shell: Option<PathBuf>) {
if let Some(default_shell) = default_shell.take() {
self.default_shell = default_shell;
}
}
pub fn update_default_editor(&mut self, mut default_editor: Option<PathBuf>) {
if let Some(default_editor) = default_editor.take() {
self.default_editor = Some(default_editor);
}
}
pub fn update_copy_options(&mut self, copy_options: &CopyOptions) {
self.clipboard_provider = match &copy_options.command {

View file

@ -251,11 +251,12 @@ fn create_new_tab(size: Size, default_mode: ModeInfo) -> Tab {
terminal_emulator_colors,
terminal_emulator_color_codes,
(vec![], vec![]),
None,
PathBuf::from("my_default_shell"),
debug,
arrow_fonts,
styled_underlines,
explicitly_disable_kitty_keyboard_protocol,
None,
);
tab.apply_layout(
TiledPaneLayout::default(),
@ -333,11 +334,12 @@ fn create_new_tab_with_swap_layouts(
terminal_emulator_colors,
terminal_emulator_color_codes,
swap_layouts,
None,
PathBuf::from("my_default_shell"),
debug,
arrow_fonts,
styled_underlines,
explicitly_disable_kitty_keyboard_protocol,
None,
);
let (
base_layout,
@ -416,11 +418,12 @@ fn create_new_tab_with_os_api(
terminal_emulator_colors,
terminal_emulator_color_codes,
(vec![], vec![]), // swap layouts
None,
PathBuf::from("my_default_shell"),
debug,
arrow_fonts,
styled_underlines,
explicitly_disable_kitty_keyboard_protocol,
None,
);
tab.apply_layout(
TiledPaneLayout::default(),
@ -485,11 +488,12 @@ fn create_new_tab_with_layout(size: Size, default_mode: ModeInfo, layout: &str)
terminal_emulator_colors,
terminal_emulator_color_codes,
(vec![], vec![]), // swap layouts
None,
PathBuf::from("my_default_shell"),
debug,
arrow_fonts,
styled_underlines,
explicitly_disable_kitty_keyboard_protocol,
None,
);
let pane_ids = tab_layout
.extract_run_instructions()
@ -568,11 +572,12 @@ fn create_new_tab_with_mock_pty_writer(
terminal_emulator_colors,
terminal_emulator_color_codes,
(vec![], vec![]), // swap layouts
None,
PathBuf::from("my_default_shell"),
debug,
arrow_fonts,
styled_underlines,
explicitly_disable_kitty_keyboard_protocol,
None,
);
tab.apply_layout(
TiledPaneLayout::default(),
@ -642,11 +647,12 @@ fn create_new_tab_with_sixel_support(
terminal_emulator_colors,
terminal_emulator_color_codes,
(vec![], vec![]), // swap layouts
None,
PathBuf::from("my_default_shell"),
debug,
arrow_fonts,
styled_underlines,
explicitly_disable_kitty_keyboard_protocol,
None,
);
tab.apply_layout(
TiledPaneLayout::default(),

View file

@ -191,11 +191,12 @@ fn create_new_tab(size: Size, stacked_resize: bool) -> Tab {
terminal_emulator_colors,
terminal_emulator_color_codes,
(vec![], vec![]), // swap layouts
None,
PathBuf::from("my_default_shell"),
debug,
arrow_fonts,
styled_underlines,
explicitly_disable_kitty_keyboard_protocol,
None,
);
tab.apply_layout(
TiledPaneLayout::default(),
@ -257,11 +258,12 @@ fn create_new_tab_with_layout(size: Size, layout: TiledPaneLayout) -> Tab {
terminal_emulator_colors,
terminal_emulator_color_codes,
(vec![], vec![]), // swap layouts
None,
PathBuf::from("my_default_shell"),
debug,
arrow_fonts,
styled_underlines,
explicitly_disable_kitty_keyboard_protocol,
None,
);
let mut new_terminal_ids = vec![];
for i in 0..layout.extract_run_instructions().len() {
@ -329,11 +331,12 @@ fn create_new_tab_with_cell_size(
terminal_emulator_colors,
terminal_emulator_color_codes,
(vec![], vec![]), // swap layouts
None,
PathBuf::from("my_default_shell"),
debug,
arrow_fonts,
styled_underlines,
explicitly_disable_kitty_keyboard_protocol,
None,
);
tab.apply_layout(
TiledPaneLayout::default(),

View file

@ -261,7 +261,7 @@ fn create_new_screen(size: Size) -> Screen {
let copy_options = CopyOptions::default();
let default_layout = Box::new(Layout::default());
let default_layout_name = None;
let default_shell = None;
let default_shell = PathBuf::from("my_default_shell");
let session_serialization = true;
let serialize_pane_viewport = false;
let scrollback_lines_to_serialize = None;
@ -293,6 +293,7 @@ fn create_new_screen(size: Size) -> Screen {
layout_dir,
explicitly_disable_kitty_keyboard_protocol,
stacked_resize,
None,
);
screen
}

View file

@ -438,6 +438,10 @@ pub struct ModeUpdatePayload {
pub session_name: ::core::option::Option<::prost::alloc::string::String>,
#[prost(enumeration = "super::input_mode::InputMode", optional, tag = "6")]
pub base_mode: ::core::option::Option<i32>,
#[prost(string, optional, tag = "7")]
pub editor: ::core::option::Option<::prost::alloc::string::String>,
#[prost(string, optional, tag = "8")]
pub shell: ::core::option::Option<::prost::alloc::string::String>,
}
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]

View file

@ -1150,6 +1150,8 @@ pub struct ModeInfo {
pub style: Style,
pub capabilities: PluginCapabilities,
pub session_name: Option<String>,
pub editor: Option<PathBuf>,
pub shell: Option<PathBuf>,
}
impl ModeInfo {

View file

@ -43,6 +43,8 @@ mod not_wasm {
style: attributes.style,
capabilities,
session_name,
editor: None,
shell: None,
}
}

View file

@ -322,6 +322,8 @@ message ModeUpdatePayload {
bool arrow_fonts_support = 4;
optional string session_name = 5;
optional input_mode.InputMode base_mode = 6;
optional string editor = 7;
optional string shell = 8;
}
message InputModeKeybinds {

View file

@ -1157,6 +1157,10 @@ impl TryFrom<ProtobufModeUpdatePayload> for ModeInfo {
.and_then(|m| m.try_into().ok())
.ok_or("malformed payload for mode_info")?;
let session_name = protobuf_mode_update_payload.session_name;
let editor = protobuf_mode_update_payload
.editor
.map(|e| PathBuf::from(e));
let shell = protobuf_mode_update_payload.shell.map(|s| PathBuf::from(s));
let capabilities = PluginCapabilities {
arrow_fonts: protobuf_mode_update_payload.arrow_fonts_support,
};
@ -1167,6 +1171,8 @@ impl TryFrom<ProtobufModeUpdatePayload> for ModeInfo {
capabilities,
session_name,
base_mode,
editor,
shell,
};
Ok(mode_info)
}
@ -1182,6 +1188,8 @@ impl TryFrom<ModeInfo> for ProtobufModeUpdatePayload {
let style: ProtobufStyle = mode_info.style.try_into()?;
let arrow_fonts_support: bool = mode_info.capabilities.arrow_fonts;
let session_name = mode_info.session_name;
let editor = mode_info.editor.map(|e| e.display().to_string());
let shell = mode_info.shell.map(|s| s.display().to_string());
let mut protobuf_input_mode_keybinds: Vec<ProtobufInputModeKeybinds> = vec![];
for (input_mode, input_mode_keybinds) in mode_info.keybinds {
let mode: ProtobufInputMode = input_mode.try_into()?;
@ -1213,6 +1221,8 @@ impl TryFrom<ModeInfo> for ProtobufModeUpdatePayload {
arrow_fonts_support,
session_name,
base_mode: base_mode.map(|b_m| b_m as i32),
editor,
shell,
})
}
}
@ -1455,6 +1465,8 @@ fn serialize_mode_update_event_with_non_default_values() {
capabilities: PluginCapabilities { arrow_fonts: false },
session_name: Some("my awesome test session".to_owned()),
base_mode: Some(InputMode::Locked),
editor: Some(PathBuf::from("my_awesome_editor")),
shell: Some(PathBuf::from("my_awesome_shell")),
});
let protobuf_event: ProtobufEvent = mode_update_event.clone().try_into().unwrap();
let serialized_protobuf_event = protobuf_event.encode_to_vec();