fix(ux): some filepicker improvements (#4007)

* allow closing plugin pane after replacing it

* start of strider improvements

* improve strider's ux

* fix selected text ui component

* style(fmt): rustfmt

* style(fmt): rustfmt
This commit is contained in:
Aram Drevekenin 2025-02-20 10:03:34 +01:00 committed by GitHub
parent 6c39e2ff0f
commit d1a4509345
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 276 additions and 115 deletions

View file

@ -30,14 +30,14 @@ impl FileListView {
self.path.pop(); self.path.pop();
self.path_is_dir = true; self.path_is_dir = true;
self.files.clear(); self.files.clear();
self.reset_selected(); self.clear_selected();
refresh_directory(&self.path); refresh_directory(&self.path);
} }
pub fn descend_to_root_path(&mut self) { pub fn descend_to_root_path(&mut self) {
self.path.clear(); self.path.clear();
self.path_is_dir = true; self.path_is_dir = true;
self.files.clear(); self.files.clear();
self.reset_selected(); self.clear_selected();
refresh_directory(&self.path); refresh_directory(&self.path);
} }
pub fn enter_dir(&mut self, entry: &FsEntry) { pub fn enter_dir(&mut self, entry: &FsEntry) {
@ -46,10 +46,10 @@ impl FileListView {
self.path = path; self.path = path;
self.path_is_dir = is_dir; self.path_is_dir = is_dir;
self.files.clear(); self.files.clear();
self.reset_selected(); self.clear_selected();
} }
pub fn reset_selected(&mut self) { pub fn clear_selected(&mut self) {
*self.selected_mut() = self.selected().unwrap_or(0); self.cursor_hist.remove(&self.path);
} }
pub fn update_files( pub fn update_files(
&mut self, &mut self,

View file

@ -32,7 +32,7 @@ impl ZellijPlugin for State {
EventType::Timer, EventType::Timer,
EventType::FileSystemUpdate, EventType::FileSystemUpdate,
]); ]);
self.file_list_view.reset_selected(); self.file_list_view.clear_selected();
// the caller_cwd might be different from the initial_cwd if this plugin was defined as an // the caller_cwd might be different from the initial_cwd if this plugin was defined as an
// alias, with access to a certain part of the file system (often broader) and was called // alias, with access to a certain part of the file system (often broader) and was called
// from an individual pane somewhere inside this broad scope - in this case, we want to // from an individual pane somewhere inside this broad scope - in this case, we want to
@ -73,7 +73,11 @@ impl ZellijPlugin for State {
should_render = true; should_render = true;
}, },
BareKey::Esc if key.has_no_modifiers() => { BareKey::Esc if key.has_no_modifiers() => {
self.clear_search_term_or_descend(); if self.is_searching {
self.clear_search_term();
} else {
self.file_list_view.clear_selected();
}
should_render = true; should_render = true;
}, },
BareKey::Char('c') if key.has_modifiers(&[KeyModifier::Ctrl]) => { BareKey::Char('c') if key.has_modifiers(&[KeyModifier::Ctrl]) => {
@ -87,15 +91,11 @@ impl ZellijPlugin for State {
self.move_selection_down(); self.move_selection_down();
should_render = true; should_render = true;
}, },
BareKey::Enter BareKey::Right | BareKey::Tab | BareKey::Enter if key.has_no_modifiers() => {
if key.has_no_modifiers() && self.handling_filepick_request_from.is_some() => self.traverse_dir();
{ should_render = true;
self.send_filepick_response();
}, },
BareKey::Enter if key.has_no_modifiers() => { BareKey::Right if key.has_no_modifiers() => {
self.open_selected_path();
},
BareKey::Right | BareKey::Tab if key.has_no_modifiers() => {
self.traverse_dir(); self.traverse_dir();
should_render = true; should_render = true;
}, },
@ -123,6 +123,12 @@ impl ZellijPlugin for State {
self.handle_left_click(line); self.handle_left_click(line);
should_render = true; should_render = true;
}, },
Mouse::Hover(line, _) => {
if line >= 0 {
self.handle_mouse_hover(line);
should_render = true;
}
},
_ => {}, _ => {},
}, },
_ => { _ => {

View file

@ -14,9 +14,6 @@ pub struct State {
pub file_list_view: FileListView, pub file_list_view: FileListView,
pub search_view: SearchView, pub search_view: SearchView,
pub hide_hidden_files: bool, pub hide_hidden_files: bool,
pub loading: bool,
pub loading_animation_offset: u8,
pub should_open_floating: bool,
pub current_rows: Option<usize>, pub current_rows: Option<usize>,
pub handling_filepick_request_from: Option<(PipeSource, BTreeMap<String, String>)>, pub handling_filepick_request_from: Option<(PipeSource, BTreeMap<String, String>)>,
pub initial_cwd: PathBuf, // TODO: get this from zellij pub initial_cwd: PathBuf, // TODO: get this from zellij
@ -50,6 +47,12 @@ impl State {
.update_search_results(&self.search_term, &self.file_list_view.files); .update_search_results(&self.search_term, &self.file_list_view.files);
} }
} }
pub fn clear_search_term(&mut self) {
self.search_term.clear();
self.search_view
.update_search_results(&self.search_term, &self.file_list_view.files);
self.is_searching = false;
}
pub fn clear_search_term_or_descend(&mut self) { pub fn clear_search_term_or_descend(&mut self) {
if self.search_term.is_empty() { if self.search_term.is_empty() {
self.descend_to_previous_path(); self.descend_to_previous_path();
@ -85,7 +88,7 @@ impl State {
); );
let prev_selected = self.search_view.selected_search_result; let prev_selected = self.search_view.selected_search_result;
self.search_view.selected_search_result = self.search_view.selected_search_result =
(line as usize).saturating_sub(2) + start_index; (line as usize).saturating_sub(4) + start_index;
if prev_selected == self.search_view.selected_search_result { if prev_selected == self.search_view.selected_search_result {
self.traverse_dir(); self.traverse_dir();
} }
@ -97,13 +100,35 @@ impl State {
); );
let prev_selected = self.file_list_view.selected(); let prev_selected = self.file_list_view.selected();
*self.file_list_view.selected_mut() = *self.file_list_view.selected_mut() =
(line as usize).saturating_sub(2) + start_index; (line as usize).saturating_sub(4) + start_index;
if prev_selected == self.file_list_view.selected() { if prev_selected == self.file_list_view.selected() {
self.traverse_dir(); self.traverse_dir();
} }
} }
} }
} }
pub fn handle_mouse_hover(&mut self, line: isize) {
if let Some(current_rows) = self.current_rows {
let rows_for_list = current_rows.saturating_sub(5);
if self.is_searching {
let (start_index, _selected_index_in_range, _end_index) = calculate_list_bounds(
self.search_view.search_result_count(),
rows_for_list,
Some(self.search_view.selected_search_result),
);
self.search_view.selected_search_result =
(line as usize).saturating_sub(4) + start_index;
} else {
let (start_index, _selected_index_in_range, _end_index) = calculate_list_bounds(
self.file_list_view.files.len(),
rows_for_list,
self.file_list_view.selected(),
);
*self.file_list_view.selected_mut() =
(line as usize).saturating_sub(4) + start_index;
}
}
}
pub fn descend_to_previous_path(&mut self) { pub fn descend_to_previous_path(&mut self) {
self.search_term.clear(); self.search_term.clear();
self.search_view.clear_and_reset_selection(); self.search_view.clear_and_reset_selection();
@ -134,8 +159,17 @@ impl State {
FsEntry::File(_p, _) => { FsEntry::File(_p, _) => {
self.file_list_view.enter_dir(&entry); self.file_list_view.enter_dir(&entry);
self.search_view.clear_and_reset_selection(); self.search_view.clear_and_reset_selection();
if self.handling_filepick_request_from.is_some() {
self.send_filepick_response();
} else {
self.open_selected_path();
}
}, },
} }
} else if self.handling_filepick_request_from.is_some() {
self.send_filepick_response();
} else {
self.open_selected_path();
} }
self.is_searching = false; self.is_searching = false;
self.search_term.clear(); self.search_term.clear();
@ -147,20 +181,37 @@ impl State {
} }
pub fn open_selected_path(&mut self) { pub fn open_selected_path(&mut self) {
if self.file_list_view.path_is_dir { if self.file_list_view.path_is_dir {
open_terminal(&self.file_list_view.path); if self.close_on_selection {
open_terminal_in_place_of_plugin(&self.file_list_view.path, true);
} else {
open_terminal(&self.file_list_view.path);
}
} else { } else {
if let Some(parent_folder) = self.file_list_view.path.parent() { if let Some(parent_folder) = self.file_list_view.path.parent() {
open_file( if self.close_on_selection {
FileToOpen::new(&self.file_list_view.path).with_cwd(parent_folder.into()), open_file_in_place_of_plugin(
BTreeMap::new(), FileToOpen::new(&self.file_list_view.path).with_cwd(parent_folder.into()),
); true,
BTreeMap::new(),
);
} else {
open_file(
FileToOpen::new(&self.file_list_view.path).with_cwd(parent_folder.into()),
BTreeMap::new(),
);
}
} else { } else {
open_file(FileToOpen::new(&self.file_list_view.path), BTreeMap::new()); if self.close_on_selection {
open_file_in_place_of_plugin(
FileToOpen::new(&self.file_list_view.path),
true,
BTreeMap::new(),
);
} else {
open_file(FileToOpen::new(&self.file_list_view.path), BTreeMap::new());
}
} }
} }
if self.close_on_selection {
close_self();
}
} }
pub fn send_filepick_response(&mut self) { pub fn send_filepick_response(&mut self) {
let selected_path = self.initial_cwd.join( let selected_path = self.initial_cwd.join(

View file

@ -256,15 +256,26 @@ fn host_run_plugin_command(caller: Caller<'_, PluginEnv>) {
PluginCommand::OpenTerminalInPlace(cwd) => { PluginCommand::OpenTerminalInPlace(cwd) => {
open_terminal_in_place(env, cwd.path.try_into()?) open_terminal_in_place(env, cwd.path.try_into()?)
}, },
PluginCommand::OpenTerminalInPlaceOfPlugin(cwd) => { PluginCommand::OpenTerminalInPlaceOfPlugin(cwd, close_plugin_after_replace) => {
open_terminal_in_place_of_plugin(env, cwd.path.try_into()?) open_terminal_in_place_of_plugin(
env,
cwd.path.try_into()?,
close_plugin_after_replace,
)
}, },
PluginCommand::OpenCommandPaneInPlace(command_to_run, context) => { PluginCommand::OpenCommandPaneInPlace(command_to_run, context) => {
open_command_pane_in_place(env, command_to_run, context) open_command_pane_in_place(env, command_to_run, context)
}, },
PluginCommand::OpenCommandPaneInPlaceOfPlugin(command_to_run, context) => { PluginCommand::OpenCommandPaneInPlaceOfPlugin(
open_command_pane_in_place_of_plugin(env, command_to_run, context) command_to_run,
}, close_plugin_after_replace,
context,
) => open_command_pane_in_place_of_plugin(
env,
command_to_run,
close_plugin_after_replace,
context,
),
PluginCommand::RenameSession(new_session_name) => { PluginCommand::RenameSession(new_session_name) => {
rename_session(env, new_session_name) rename_session(env, new_session_name)
}, },
@ -413,9 +424,16 @@ fn host_run_plugin_command(caller: Caller<'_, PluginEnv>) {
floating_pane_coordinates, floating_pane_coordinates,
context, context,
), ),
PluginCommand::OpenFileInPlaceOfPlugin(file_to_open, context) => { PluginCommand::OpenFileInPlaceOfPlugin(
open_file_in_place_of_plugin(env, file_to_open, context) file_to_open,
}, close_plugin_after_replace,
context,
) => open_file_in_place_of_plugin(
env,
file_to_open,
close_plugin_after_replace,
context,
),
}, },
(PermissionStatus::Denied, permission) => { (PermissionStatus::Denied, permission) => {
log::error!( log::error!(
@ -703,6 +721,7 @@ fn open_file_floating_near_plugin(
fn open_file_in_place_of_plugin( fn open_file_in_place_of_plugin(
env: &PluginEnv, env: &PluginEnv,
file_to_open: FileToOpen, file_to_open: FileToOpen,
close_plugin_after_replace: bool,
context: BTreeMap<String, String>, context: BTreeMap<String, String>,
) { ) {
let cwd = file_to_open let cwd = file_to_open
@ -719,6 +738,7 @@ fn open_file_in_place_of_plugin(
let pty_instr = PtyInstruction::SpawnInPlaceTerminal( let pty_instr = PtyInstruction::SpawnInPlaceTerminal(
Some(open_file), Some(open_file),
Some(title), Some(title),
close_plugin_after_replace,
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)), ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
); );
let _ = env.senders.send_to_pty(pty_instr); let _ = env.senders.send_to_pty(pty_instr);
@ -828,7 +848,11 @@ fn open_terminal_in_place(env: &PluginEnv, cwd: PathBuf) {
apply_action!(action, error_msg, env); apply_action!(action, error_msg, env);
} }
fn open_terminal_in_place_of_plugin(env: &PluginEnv, cwd: PathBuf) { fn open_terminal_in_place_of_plugin(
env: &PluginEnv,
cwd: PathBuf,
close_plugin_after_replace: bool,
) {
let cwd = env.plugin_cwd.join(cwd); let cwd = env.plugin_cwd.join(cwd);
let mut default_shell = env.default_shell.clone().unwrap_or_else(|| { let mut default_shell = env.default_shell.clone().unwrap_or_else(|| {
TerminalAction::RunCommand(RunCommand { TerminalAction::RunCommand(RunCommand {
@ -843,6 +867,7 @@ fn open_terminal_in_place_of_plugin(env: &PluginEnv, cwd: PathBuf) {
.send_to_pty(PtyInstruction::SpawnInPlaceTerminal( .send_to_pty(PtyInstruction::SpawnInPlaceTerminal(
Some(default_shell), Some(default_shell),
name, name,
close_plugin_after_replace,
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)), ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
)); ));
} }
@ -850,6 +875,7 @@ fn open_terminal_in_place_of_plugin(env: &PluginEnv, cwd: PathBuf) {
fn open_command_pane_in_place_of_plugin( fn open_command_pane_in_place_of_plugin(
env: &PluginEnv, env: &PluginEnv,
command_to_run: CommandToRun, command_to_run: CommandToRun,
close_plugin_after_replace: bool,
context: BTreeMap<String, String>, context: BTreeMap<String, String>,
) { ) {
let command = command_to_run.path; let command = command_to_run.path;
@ -878,6 +904,7 @@ fn open_command_pane_in_place_of_plugin(
.send_to_pty(PtyInstruction::SpawnInPlaceTerminal( .send_to_pty(PtyInstruction::SpawnInPlaceTerminal(
Some(run_cmd), Some(run_cmd),
name, name,
close_plugin_after_replace,
ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)), ClientTabIndexOrPaneId::PaneId(PaneId::Plugin(env.plugin_id)),
)); ));
} }

View file

@ -78,6 +78,7 @@ pub enum PtyInstruction {
SpawnInPlaceTerminal( SpawnInPlaceTerminal(
Option<TerminalAction>, Option<TerminalAction>,
Option<String>, Option<String>,
bool, // close replaced pane
ClientTabIndexOrPaneId, ClientTabIndexOrPaneId,
), // String is an optional pane name ), // String is an optional pane name
DumpLayout(SessionLayoutMetadata, ClientId), DumpLayout(SessionLayoutMetadata, ClientId),
@ -278,6 +279,7 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
PtyInstruction::SpawnInPlaceTerminal( PtyInstruction::SpawnInPlaceTerminal(
terminal_action, terminal_action,
name, name,
close_replaced_pane,
client_id_tab_index_or_pane_id, client_id_tab_index_or_pane_id,
) => { ) => {
let err_context = || { let err_context = || {
@ -318,6 +320,7 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
hold_for_command, hold_for_command,
pane_title, pane_title,
invoked_with, invoked_with,
close_replaced_pane,
client_id_tab_index_or_pane_id, client_id_tab_index_or_pane_id,
)) ))
.with_context(err_context)?; .with_context(err_context)?;
@ -333,6 +336,7 @@ pub(crate) fn pty_thread_main(mut pty: Pty, layout: Box<Layout>) -> Result<()> {
hold_for_command, hold_for_command,
pane_title, pane_title,
invoked_with, invoked_with,
close_replaced_pane,
client_id_tab_index_or_pane_id, client_id_tab_index_or_pane_id,
)) ))
.with_context(err_context)?; .with_context(err_context)?;

View file

@ -312,11 +312,13 @@ pub(crate) fn route_action(
Some(pane_id) => PtyInstruction::SpawnInPlaceTerminal( Some(pane_id) => PtyInstruction::SpawnInPlaceTerminal(
Some(open_file), Some(open_file),
Some(title), Some(title),
false,
ClientTabIndexOrPaneId::PaneId(pane_id), ClientTabIndexOrPaneId::PaneId(pane_id),
), ),
None => PtyInstruction::SpawnInPlaceTerminal( None => PtyInstruction::SpawnInPlaceTerminal(
Some(open_file), Some(open_file),
Some(title), Some(title),
false,
ClientTabIndexOrPaneId::ClientId(client_id), ClientTabIndexOrPaneId::ClientId(client_id),
), ),
}, },
@ -389,6 +391,7 @@ pub(crate) fn route_action(
.send_to_pty(PtyInstruction::SpawnInPlaceTerminal( .send_to_pty(PtyInstruction::SpawnInPlaceTerminal(
run_cmd, run_cmd,
name, name,
false,
ClientTabIndexOrPaneId::PaneId(pane_id), ClientTabIndexOrPaneId::PaneId(pane_id),
)) ))
.with_context(err_context)?; .with_context(err_context)?;
@ -398,6 +401,7 @@ pub(crate) fn route_action(
.send_to_pty(PtyInstruction::SpawnInPlaceTerminal( .send_to_pty(PtyInstruction::SpawnInPlaceTerminal(
run_cmd, run_cmd,
name, name,
false,
ClientTabIndexOrPaneId::ClientId(client_id), ClientTabIndexOrPaneId::ClientId(client_id),
)) ))
.with_context(err_context)?; .with_context(err_context)?;

View file

@ -349,6 +349,7 @@ pub enum ScreenInstruction {
HoldForCommand, HoldForCommand,
Option<InitialTitle>, Option<InitialTitle>,
Option<Run>, Option<Run>,
bool, // close replaced pane
ClientTabIndexOrPaneId, ClientTabIndexOrPaneId,
), ),
DumpLayoutToHd, DumpLayoutToHd,
@ -2397,10 +2398,16 @@ impl Screen {
hold_for_command: HoldForCommand, hold_for_command: HoldForCommand,
run: Option<Run>, run: Option<Run>,
pane_title: Option<InitialTitle>, pane_title: Option<InitialTitle>,
close_replaced_pane: bool,
client_id_tab_index_or_pane_id: ClientTabIndexOrPaneId, client_id_tab_index_or_pane_id: ClientTabIndexOrPaneId,
) -> Result<()> { ) -> Result<()> {
let suppress_pane = |tab: &mut Tab, pane_id: PaneId, new_pane_id: PaneId| { let suppress_pane = |tab: &mut Tab, pane_id: PaneId, new_pane_id: PaneId| {
let _ = tab.suppress_pane_and_replace_with_pid(pane_id, new_pane_id, run); let _ = tab.suppress_pane_and_replace_with_pid(
pane_id,
new_pane_id,
close_replaced_pane,
run,
);
if let Some(pane_title) = pane_title { if let Some(pane_title) = pane_title {
let _ = tab.rename_pane(pane_title.as_bytes().to_vec(), new_pane_id); let _ = tab.rename_pane(pane_title.as_bytes().to_vec(), new_pane_id);
} }
@ -4184,6 +4191,7 @@ pub(crate) fn screen_thread_main(
}); });
let run_plugin = Run::Plugin(run_plugin_or_alias); let run_plugin = Run::Plugin(run_plugin_or_alias);
let close_replaced_pane = false;
if should_be_in_place { if should_be_in_place {
if let Some(pane_id_to_replace) = pane_id_to_replace { if let Some(pane_id_to_replace) = pane_id_to_replace {
let client_tab_index_or_pane_id = let client_tab_index_or_pane_id =
@ -4193,6 +4201,7 @@ pub(crate) fn screen_thread_main(
None, None,
Some(run_plugin), Some(run_plugin),
Some(pane_title), Some(pane_title),
close_replaced_pane,
client_tab_index_or_pane_id, client_tab_index_or_pane_id,
)?; )?;
} else if let Some(client_id) = client_id { } else if let Some(client_id) = client_id {
@ -4203,6 +4212,7 @@ pub(crate) fn screen_thread_main(
None, None,
Some(run_plugin), Some(run_plugin),
Some(pane_title), Some(pane_title),
close_replaced_pane,
client_tab_index_or_pane_id, client_tab_index_or_pane_id,
)?; )?;
} else { } else {
@ -4508,6 +4518,7 @@ pub(crate) fn screen_thread_main(
hold_for_command, hold_for_command,
pane_title, pane_title,
invoked_with, invoked_with,
close_replaced_pane,
client_id_tab_index_or_pane_id, client_id_tab_index_or_pane_id,
) => { ) => {
screen.replace_pane( screen.replace_pane(
@ -4515,6 +4526,7 @@ pub(crate) fn screen_thread_main(
hold_for_command, hold_for_command,
invoked_with, invoked_with,
pane_title, pane_title,
close_replaced_pane,
client_id_tab_index_or_pane_id, client_id_tab_index_or_pane_id,
)?; )?;

View file

@ -1320,6 +1320,7 @@ impl Tab {
&mut self, &mut self,
old_pane_id: PaneId, old_pane_id: PaneId,
new_pane_id: PaneId, new_pane_id: PaneId,
close_replaced_pane: bool,
run: Option<Run>, run: Option<Run>,
) -> Result<()> { ) -> Result<()> {
// this method creates a new pane from pid and replaces it with the active pane // this method creates a new pane from pid and replaces it with the active pane
@ -1356,27 +1357,36 @@ impl Tab {
self.tiled_panes self.tiled_panes
.replace_pane(old_pane_id, Box::new(new_pane)) .replace_pane(old_pane_id, Box::new(new_pane))
}; };
match replaced_pane { if close_replaced_pane {
Some(replaced_pane) => { if let Some(pid) = replaced_pane.as_ref().map(|p| p.pid()) {
let _ = resize_pty!( self.senders
replaced_pane, .send_to_pty(PtyInstruction::ClosePane(pid))
self.os_api, .with_context(err_context)?;
self.senders, }
self.character_cell_size drop(replaced_pane);
); } else {
let is_scrollback_editor = false; match replaced_pane {
self.suppressed_panes.insert( Some(replaced_pane) => {
PaneId::Terminal(new_pane_id), let _ = resize_pty!(
(is_scrollback_editor, replaced_pane), replaced_pane,
); self.os_api,
}, self.senders,
None => { self.character_cell_size
Err::<(), _>(anyhow!( );
"Could not find editor pane to replace - is no pane focused?" let is_scrollback_editor = false;
)) self.suppressed_panes.insert(
.with_context(err_context) PaneId::Terminal(new_pane_id),
.non_fatal(); (is_scrollback_editor, replaced_pane),
}, );
},
None => {
Err::<(), _>(anyhow!(
"Could not find editor pane to replace - is no pane focused?"
))
.with_context(err_context)
.non_fatal();
},
}
} }
}, },
PaneId::Plugin(plugin_pid) => { PaneId::Plugin(plugin_pid) => {
@ -1410,27 +1420,31 @@ impl Tab {
self.tiled_panes self.tiled_panes
.replace_pane(old_pane_id, Box::new(new_pane)) .replace_pane(old_pane_id, Box::new(new_pane))
}; };
match replaced_pane { if close_replaced_pane {
Some(replaced_pane) => { drop(replaced_pane);
let _ = resize_pty!( } else {
replaced_pane, match replaced_pane {
self.os_api, Some(replaced_pane) => {
self.senders, let _ = resize_pty!(
self.character_cell_size replaced_pane,
); self.os_api,
let is_scrollback_editor = false; self.senders,
self.suppressed_panes.insert( self.character_cell_size
PaneId::Plugin(plugin_pid), );
(is_scrollback_editor, replaced_pane), let is_scrollback_editor = false;
); self.suppressed_panes.insert(
}, PaneId::Plugin(plugin_pid),
None => { (is_scrollback_editor, replaced_pane),
Err::<(), _>(anyhow!( );
"Could not find editor pane to replace - is no pane focused?" },
)) None => {
.with_context(err_context) Err::<(), _>(anyhow!(
.non_fatal(); "Could not find editor pane to replace - is no pane focused?"
}, ))
.with_context(err_context)
.non_fatal();
},
}
} }
}, },
} }

View file

@ -58,7 +58,14 @@ pub fn stringify_text(
break; break;
} }
text_width += character_width; text_width += character_width;
if !text.indices.is_empty() {
if text.selected {
// we do this so that selected text will appear selected
// even if it does not have color indices
stringified.push_str(&format!("{}", base_text_style));
}
if !text.indices.is_empty() || text.selected {
let character_with_styling = let character_with_styling =
color_index_character(character, i, &text, style, base_text_style); color_index_character(character, i, &text, style, base_text_style);
stringified.push_str(&character_with_styling); stringified.push_str(&character_with_styling);

View file

@ -126,8 +126,13 @@ pub fn open_file_floating_near_plugin(
} }
/// Open a file in the user's default `$EDITOR`, replacing the plugin pane /// Open a file in the user's default `$EDITOR`, replacing the plugin pane
pub fn open_file_in_place_of_plugin(file_to_open: FileToOpen, context: BTreeMap<String, String>) { pub fn open_file_in_place_of_plugin(
let plugin_command = PluginCommand::OpenFileInPlaceOfPlugin(file_to_open, context); file_to_open: FileToOpen,
close_plugin_after_replace: bool,
context: BTreeMap<String, String>,
) {
let plugin_command =
PluginCommand::OpenFileInPlaceOfPlugin(file_to_open, close_plugin_after_replace, context);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec()); object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() }; unsafe { host_run_plugin_command() };
@ -190,9 +195,10 @@ pub fn open_terminal_in_place<P: AsRef<Path>>(path: P) {
/// Open a new terminal pane to the specified location on the host filesystem, temporarily /// Open a new terminal pane to the specified location on the host filesystem, temporarily
/// replacing the plugin pane /// replacing the plugin pane
pub fn open_terminal_in_place_of_plugin<P: AsRef<Path>>(path: P) { pub fn open_terminal_in_place_of_plugin<P: AsRef<Path>>(path: P, close_plugin_after_replace: bool) {
let file_to_open = FileToOpen::new(path.as_ref().to_path_buf()); let file_to_open = FileToOpen::new(path.as_ref().to_path_buf());
let plugin_command = PluginCommand::OpenTerminalInPlaceOfPlugin(file_to_open); let plugin_command =
PluginCommand::OpenTerminalInPlaceOfPlugin(file_to_open, close_plugin_after_replace);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec()); object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() }; unsafe { host_run_plugin_command() };
@ -260,9 +266,14 @@ pub fn open_command_pane_in_place(command_to_run: CommandToRun, context: BTreeMa
/// plugin pane rather than whichever pane the user is focused on /// plugin pane rather than whichever pane the user is focused on
pub fn open_command_pane_in_place_of_plugin( pub fn open_command_pane_in_place_of_plugin(
command_to_run: CommandToRun, command_to_run: CommandToRun,
close_plugin_after_replace: bool,
context: BTreeMap<String, String>, context: BTreeMap<String, String>,
) { ) {
let plugin_command = PluginCommand::OpenCommandPaneInPlaceOfPlugin(command_to_run, context); let plugin_command = PluginCommand::OpenCommandPaneInPlaceOfPlugin(
command_to_run,
close_plugin_after_replace,
context,
);
let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap(); let protobuf_plugin_command: ProtobufPluginCommand = plugin_command.try_into().unwrap();
object_to_stdout(&protobuf_plugin_command.encode_to_vec()); object_to_stdout(&protobuf_plugin_command.encode_to_vec());
unsafe { host_run_plugin_command() }; unsafe { host_run_plugin_command() };

View file

@ -219,6 +219,8 @@ pub struct OpenFileInPlaceOfPluginPayload {
pub floating_pane_coordinates: ::core::option::Option<FloatingPaneCoordinates>, pub floating_pane_coordinates: ::core::option::Option<FloatingPaneCoordinates>,
#[prost(message, repeated, tag = "3")] #[prost(message, repeated, tag = "3")]
pub context: ::prost::alloc::vec::Vec<ContextItem>, pub context: ::prost::alloc::vec::Vec<ContextItem>,
#[prost(bool, tag = "4")]
pub close_plugin_after_replace: bool,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
@ -247,6 +249,8 @@ pub struct OpenCommandPaneInPlaceOfPluginPayload {
pub command_to_run: ::core::option::Option<super::command::Command>, pub command_to_run: ::core::option::Option<super::command::Command>,
#[prost(message, repeated, tag = "3")] #[prost(message, repeated, tag = "3")]
pub context: ::prost::alloc::vec::Vec<ContextItem>, pub context: ::prost::alloc::vec::Vec<ContextItem>,
#[prost(bool, tag = "4")]
pub close_plugin_after_replace: bool,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]
@ -265,6 +269,8 @@ pub struct OpenTerminalInPlaceOfPluginPayload {
pub file_to_open: ::core::option::Option<super::file::File>, pub file_to_open: ::core::option::Option<super::file::File>,
#[prost(message, repeated, tag = "3")] #[prost(message, repeated, tag = "3")]
pub context: ::prost::alloc::vec::Vec<ContextItem>, pub context: ::prost::alloc::vec::Vec<ContextItem>,
#[prost(bool, tag = "4")]
pub close_plugin_after_replace: bool,
} }
#[allow(clippy::derive_partial_eq_without_eq)] #[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)] #[derive(Clone, PartialEq, ::prost::Message)]

View file

@ -2299,10 +2299,11 @@ pub enum PluginCommand {
OpenCommandPaneNearPlugin(CommandToRun, Context), OpenCommandPaneNearPlugin(CommandToRun, Context),
OpenTerminalNearPlugin(FileToOpen), OpenTerminalNearPlugin(FileToOpen),
OpenTerminalFloatingNearPlugin(FileToOpen, Option<FloatingPaneCoordinates>), OpenTerminalFloatingNearPlugin(FileToOpen, Option<FloatingPaneCoordinates>),
OpenTerminalInPlaceOfPlugin(FileToOpen), OpenTerminalInPlaceOfPlugin(FileToOpen, bool), // bool -> close_plugin_after_replace
OpenCommandPaneFloatingNearPlugin(CommandToRun, Option<FloatingPaneCoordinates>, Context), OpenCommandPaneFloatingNearPlugin(CommandToRun, Option<FloatingPaneCoordinates>, Context),
OpenCommandPaneInPlaceOfPlugin(CommandToRun, Context), OpenCommandPaneInPlaceOfPlugin(CommandToRun, bool, Context), // bool ->
// close_plugin_after_replace
OpenFileNearPlugin(FileToOpen, Context), OpenFileNearPlugin(FileToOpen, Context),
OpenFileFloatingNearPlugin(FileToOpen, Option<FloatingPaneCoordinates>, Context), OpenFileFloatingNearPlugin(FileToOpen, Option<FloatingPaneCoordinates>, Context),
OpenFileInPlaceOfPlugin(FileToOpen, Context), OpenFileInPlaceOfPlugin(FileToOpen, bool, Context), // bool -> close_plugin_after_replace
} }

View file

@ -243,6 +243,7 @@ message OpenFileInPlaceOfPluginPayload {
file.File file_to_open = 1; file.File file_to_open = 1;
optional FloatingPaneCoordinates floating_pane_coordinates = 2; optional FloatingPaneCoordinates floating_pane_coordinates = 2;
repeated ContextItem context = 3; repeated ContextItem context = 3;
bool close_plugin_after_replace = 4;
} }
message OpenFileFloatingNearPluginPayload { message OpenFileFloatingNearPluginPayload {
@ -260,6 +261,7 @@ message OpenFileNearPluginPayload {
message OpenCommandPaneInPlaceOfPluginPayload { message OpenCommandPaneInPlaceOfPluginPayload {
command.Command command_to_run = 1; command.Command command_to_run = 1;
repeated ContextItem context = 3; repeated ContextItem context = 3;
bool close_plugin_after_replace = 4;
} }
message OpenCommandPaneFloatingNearPluginPayload { message OpenCommandPaneFloatingNearPluginPayload {
@ -271,6 +273,7 @@ message OpenCommandPaneFloatingNearPluginPayload {
message OpenTerminalInPlaceOfPluginPayload { message OpenTerminalInPlaceOfPluginPayload {
file.File file_to_open = 1; file.File file_to_open = 1;
repeated ContextItem context = 3; repeated ContextItem context = 3;
bool close_plugin_after_replace = 4;
} }
message OpenTerminalFloatingNearPluginPayload { message OpenTerminalFloatingNearPluginPayload {

View file

@ -1422,6 +1422,7 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
)) => match open_terminal_in_place_of_plugin_payload.file_to_open { )) => match open_terminal_in_place_of_plugin_payload.file_to_open {
Some(file_to_open) => Ok(PluginCommand::OpenTerminalInPlaceOfPlugin( Some(file_to_open) => Ok(PluginCommand::OpenTerminalInPlaceOfPlugin(
file_to_open.try_into()?, file_to_open.try_into()?,
open_terminal_in_place_of_plugin_payload.close_plugin_after_replace,
)), )),
None => Err("Malformed open terminal in place of plugin payload"), None => Err("Malformed open terminal in place of plugin payload"),
}, },
@ -1467,6 +1468,8 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
.collect(); .collect();
Ok(PluginCommand::OpenCommandPaneInPlaceOfPlugin( Ok(PluginCommand::OpenCommandPaneInPlaceOfPlugin(
command_to_run.try_into()?, command_to_run.try_into()?,
open_command_pane_in_place_of_plugin_payload
.close_plugin_after_replace,
context, context,
)) ))
}, },
@ -1528,6 +1531,7 @@ impl TryFrom<ProtobufPluginCommand> for PluginCommand {
.collect(); .collect();
Ok(PluginCommand::OpenFileInPlaceOfPlugin( Ok(PluginCommand::OpenFileInPlaceOfPlugin(
file_to_open.try_into()?, file_to_open.try_into()?,
file_to_open_payload.close_plugin_after_replace,
context, context,
)) ))
}, },
@ -2467,16 +2471,23 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
)), )),
}) })
}, },
PluginCommand::OpenTerminalInPlaceOfPlugin(cwd) => Ok(ProtobufPluginCommand { PluginCommand::OpenTerminalInPlaceOfPlugin(cwd, close_plugin_after_replace) => {
name: CommandName::OpenTerminalInPlaceOfPlugin as i32, Ok(ProtobufPluginCommand {
payload: Some(Payload::OpenTerminalInPlaceOfPluginPayload( name: CommandName::OpenTerminalInPlaceOfPlugin as i32,
OpenTerminalInPlaceOfPluginPayload { payload: Some(Payload::OpenTerminalInPlaceOfPluginPayload(
file_to_open: Some(cwd.try_into()?), OpenTerminalInPlaceOfPluginPayload {
context: vec![], // will be added in the future file_to_open: Some(cwd.try_into()?),
}, close_plugin_after_replace,
)), context: vec![], // will be added in the future
}), },
PluginCommand::OpenCommandPaneInPlaceOfPlugin(command_to_run, context) => { )),
})
},
PluginCommand::OpenCommandPaneInPlaceOfPlugin(
command_to_run,
close_plugin_after_replace,
context,
) => {
let context: Vec<_> = context let context: Vec<_> = context
.into_iter() .into_iter()
.map(|(name, value)| ContextItem { name, value }) .map(|(name, value)| ContextItem { name, value })
@ -2486,6 +2497,7 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
payload: Some(Payload::OpenCommandPaneInPlaceOfPluginPayload( payload: Some(Payload::OpenCommandPaneInPlaceOfPluginPayload(
OpenCommandPaneInPlaceOfPluginPayload { OpenCommandPaneInPlaceOfPluginPayload {
command_to_run: Some(command_to_run.try_into()?), command_to_run: Some(command_to_run.try_into()?),
close_plugin_after_replace,
context, context,
}, },
)), )),
@ -2521,21 +2533,24 @@ impl TryFrom<PluginCommand> for ProtobufPluginCommand {
}, },
)), )),
}), }),
PluginCommand::OpenFileInPlaceOfPlugin(file_to_open, context) => { PluginCommand::OpenFileInPlaceOfPlugin(
Ok(ProtobufPluginCommand { file_to_open,
name: CommandName::OpenFileInPlaceOfPlugin as i32, close_plugin_after_replace,
payload: Some(Payload::OpenFileInPlaceOfPluginPayload( context,
OpenFileInPlaceOfPluginPayload { ) => Ok(ProtobufPluginCommand {
file_to_open: Some(file_to_open.try_into()?), name: CommandName::OpenFileInPlaceOfPlugin as i32,
floating_pane_coordinates: None, payload: Some(Payload::OpenFileInPlaceOfPluginPayload(
context: context OpenFileInPlaceOfPluginPayload {
.into_iter() file_to_open: Some(file_to_open.try_into()?),
.map(|(name, value)| ContextItem { name, value }) floating_pane_coordinates: None,
.collect(), close_plugin_after_replace,
}, context: context
)), .into_iter()
}) .map(|(name, value)| ContextItem { name, value })
}, .collect(),
},
)),
}),
} }
} }
} }