diff --git a/lapce-app/src/app.rs b/lapce-app/src/app.rs index 046061e0ea..1c204a5466 100644 --- a/lapce-app/src/app.rs +++ b/lapce-app/src/app.rs @@ -12,6 +12,7 @@ use std::{ use anyhow::{anyhow, Result}; use clap::Parser; use crossbeam_channel::Sender; +use floem::action::show_context_menu; use floem::{ cosmic_text::{Style as FontStyle, Weight}, event::{Event, EventListener, EventPropagation}, @@ -62,6 +63,7 @@ use notify::Watcher; use serde::{Deserialize, Serialize}; use tracing_subscriber::{filter::Targets, reload::Handle}; +use crate::main_split::TabCloseKind; use crate::{ about, alert, code_action::CodeActionStatus, @@ -639,6 +641,7 @@ fn editor_tab_header( let local_child = child.clone(); let child_for_close = child.clone(); let child_for_mouse_close = child.clone(); + let child_for_mouse_close_2 = child.clone(); let main_split = main_split.clone(); let plugin = plugin.clone(); let child_view = { @@ -792,6 +795,16 @@ fn editor_tab_header( EventPropagation::Continue } }) + .on_secondary_click_stop(move |_| { + let editor_tab_id = + editor_tab.with_untracked(|t| t.editor_tab_id); + + tab_secondary_click( + internal_command, + editor_tab_id, + child_for_mouse_close_2.clone(), + ); + }) .on_event_stop(EventListener::DragStart, move |_| { dragging.set(Some((i, editor_tab_id))); }) @@ -4124,3 +4137,46 @@ fn fetch_queries() -> Result<()> { Err(anyhow!("can't find support queries")) } + +fn tab_secondary_click( + internal_command: Listener, + editor_tab_id: EditorTabId, + child: EditorTabChild, +) { + let mut menu = Menu::new(""); + let child_other = child.clone(); + let child_right = child.clone(); + let child_left = child.clone(); + menu = menu + .entry(MenuItem::new("Close").action(move || { + internal_command.send(InternalCommand::EditorTabChildClose { + editor_tab_id, + child: child.clone(), + }); + })) + .entry(MenuItem::new("Close Other Tabs").action(move || { + internal_command.send(InternalCommand::EditorTabCloseByKind { + editor_tab_id, + child: child_other.clone(), + kind: TabCloseKind::CloseOther, + }); + })) + .entry(MenuItem::new("Close All Tabs").action(move || { + internal_command.send(InternalCommand::EditorTabClose { editor_tab_id }); + })) + .entry(MenuItem::new("Close Tabs to the Right").action(move || { + internal_command.send(InternalCommand::EditorTabCloseByKind { + editor_tab_id, + child: child_right.clone(), + kind: TabCloseKind::CloseToRight, + }); + })) + .entry(MenuItem::new("Close Tabs to the Left").action(move || { + internal_command.send(InternalCommand::EditorTabCloseByKind { + editor_tab_id, + child: child_left.clone(), + kind: TabCloseKind::CloseToLeft, + }); + })); + show_context_menu(menu, None); +} diff --git a/lapce-app/src/command.rs b/lapce-app/src/command.rs index c981b8d363..cf957630d8 100644 --- a/lapce-app/src/command.rs +++ b/lapce-app/src/command.rs @@ -20,6 +20,7 @@ use serde_json::Value; use strum::{EnumMessage, IntoEnumIterator}; use strum_macros::{Display, EnumIter, EnumMessage, EnumString, IntoStaticStr}; +use crate::main_split::TabCloseKind; use crate::{ alert::AlertButton, debug::RunDebugMode, @@ -624,6 +625,11 @@ pub enum InternalCommand { editor_tab_id: EditorTabId, child: EditorTabChild, }, + EditorTabCloseByKind { + editor_tab_id: EditorTabId, + child: EditorTabChild, + kind: TabCloseKind, + }, ShowCodeActions { offset: usize, mouse_click: bool, diff --git a/lapce-app/src/main_split.rs b/lapce-app/src/main_split.rs index 99ae194ead..708400798e 100644 --- a/lapce-app/src/main_split.rs +++ b/lapce-app/src/main_split.rs @@ -1917,6 +1917,60 @@ impl MainSplitData { Some(()) } + pub fn editor_tab_child_close_by_kind( + &self, + editor_tab_id: EditorTabId, + child: EditorTabChild, + kind: TabCloseKind, + ) -> Option<()> { + let tabs_to_close: Vec = { + let editor_tabs = self.editor_tabs.get_untracked(); + + let editor_tab = editor_tabs.get(&editor_tab_id).copied()?; + let editor_tab = editor_tab.get_untracked(); + match kind { + TabCloseKind::CloseOther => editor_tab + .children + .iter() + .filter_map(|x| { + if x.2 != child { + Some(x.2.clone()) + } else { + None + } + }) + .collect(), + TabCloseKind::CloseToLeft => { + let mut tabs_to_close = Vec::new(); + for child_tab in &editor_tab.children { + if child_tab.2 != child { + tabs_to_close.push(child_tab.2.clone()); + } else { + break; + } + } + tabs_to_close + } + TabCloseKind::CloseToRight => { + let mut tabs_to_close = Vec::new(); + let mut add_to_tabs = false; + for child_tab in &editor_tab.children { + if child_tab.2 != child && add_to_tabs { + tabs_to_close.push(child_tab.2.clone()); + } else { + add_to_tabs = true; + } + } + tabs_to_close + } + } + }; + for child_tab in tabs_to_close { + self.editor_tab_child_close(editor_tab_id, child_tab, false); + } + Some(()) + } + pub fn editor_tab_child_close( &self, editor_tab_id: EditorTabId, @@ -2949,3 +3003,10 @@ fn next_in_file_errors_offset( }, ) } + +#[derive(Clone, Copy, Debug)] +pub enum TabCloseKind { + CloseOther, + CloseToLeft, + CloseToRight, +} diff --git a/lapce-app/src/window_tab.rs b/lapce-app/src/window_tab.rs index 7b8ddfc1fa..f2060fd5ca 100644 --- a/lapce-app/src/window_tab.rs +++ b/lapce-app/src/window_tab.rs @@ -1584,6 +1584,17 @@ impl WindowTabData { self.main_split .editor_tab_child_close(editor_tab_id, child, false); } + InternalCommand::EditorTabCloseByKind { + editor_tab_id, + child, + kind, + } => { + self.main_split.editor_tab_child_close_by_kind( + editor_tab_id, + child, + kind, + ); + } InternalCommand::ShowCodeActions { offset, mouse_click,