Merge branch 'snaggen-primary'

This commit is contained in:
Jeremy Soller 2024-04-26 10:13:51 -06:00
commit 97523f689d
No known key found for this signature in database
GPG key ID: D02FD439211AF56F
3 changed files with 57 additions and 0 deletions

View file

@ -28,6 +28,7 @@ pub fn key_binds() -> HashMap<KeyBind, Action> {
bind!([Ctrl, Shift], Key::Character("Q".into()), WindowClose); bind!([Ctrl, Shift], Key::Character("Q".into()), WindowClose);
bind!([Ctrl, Shift], Key::Character("T".into()), TabNew); bind!([Ctrl, Shift], Key::Character("T".into()), TabNew);
bind!([Ctrl, Shift], Key::Character("V".into()), Paste); bind!([Ctrl, Shift], Key::Character("V".into()), Paste);
bind!([Shift], Key::Named(Named::Insert), PastePrimary);
bind!([Ctrl, Shift], Key::Character("W".into()), TabClose); bind!([Ctrl, Shift], Key::Character("W".into()), TabClose);
bind!([Ctrl], Key::Character(",".into()), Settings); bind!([Ctrl], Key::Character(",".into()), Settings);

View file

@ -14,6 +14,7 @@ use cosmic::{
clipboard, event, clipboard, event,
futures::SinkExt, futures::SinkExt,
keyboard::{Event as KeyEvent, Key, Modifiers}, keyboard::{Event as KeyEvent, Key, Modifiers},
mouse::{Button as MouseButton, Event as MouseEvent},
subscription::{self, Subscription}, subscription::{self, Subscription},
window, Alignment, Color, Event, Length, Limits, Padding, Point, window, Alignment, Color, Event, Length, Limits, Padding, Point,
}, },
@ -167,6 +168,7 @@ pub enum Action {
About, About,
ColorSchemes(ColorSchemeKind), ColorSchemes(ColorSchemeKind),
Copy, Copy,
CopyPrimary,
Find, Find,
PaneFocusDown, PaneFocusDown,
PaneFocusLeft, PaneFocusLeft,
@ -176,6 +178,7 @@ pub enum Action {
PaneSplitVertical, PaneSplitVertical,
PaneToggleMaximized, PaneToggleMaximized,
Paste, Paste,
PastePrimary,
ProfileOpen(ProfileId), ProfileOpen(ProfileId),
Profiles, Profiles,
SelectAll, SelectAll,
@ -211,6 +214,7 @@ impl MenuAction for Action {
Message::ToggleContextPage(ContextPage::ColorSchemes(*color_scheme_kind)) Message::ToggleContextPage(ContextPage::ColorSchemes(*color_scheme_kind))
} }
Action::Copy => Message::Copy(entity_opt), Action::Copy => Message::Copy(entity_opt),
Action::CopyPrimary => Message::CopyPrimary(entity_opt),
Action::Find => Message::Find(true), Action::Find => Message::Find(true),
Action::PaneFocusDown => Message::PaneFocusAdjacent(pane_grid::Direction::Down), Action::PaneFocusDown => Message::PaneFocusAdjacent(pane_grid::Direction::Down),
Action::PaneFocusLeft => Message::PaneFocusAdjacent(pane_grid::Direction::Left), Action::PaneFocusLeft => Message::PaneFocusAdjacent(pane_grid::Direction::Left),
@ -220,6 +224,7 @@ impl MenuAction for Action {
Action::PaneSplitVertical => Message::PaneSplit(pane_grid::Axis::Vertical), Action::PaneSplitVertical => Message::PaneSplit(pane_grid::Axis::Vertical),
Action::PaneToggleMaximized => Message::PaneToggleMaximized, Action::PaneToggleMaximized => Message::PaneToggleMaximized,
Action::Paste => Message::Paste(entity_opt), Action::Paste => Message::Paste(entity_opt),
Action::PastePrimary => Message::PastePrimary(entity_opt),
Action::ProfileOpen(profile_id) => Message::ProfileOpen(*profile_id), Action::ProfileOpen(profile_id) => Message::ProfileOpen(*profile_id),
Action::Profiles => Message::ToggleContextPage(ContextPage::Profiles), Action::Profiles => Message::ToggleContextPage(ContextPage::Profiles),
Action::SelectAll => Message::SelectAll(entity_opt), Action::SelectAll => Message::SelectAll(entity_opt),
@ -263,6 +268,7 @@ pub enum Message {
ColorSchemeTabActivate(widget::segmented_button::Entity), ColorSchemeTabActivate(widget::segmented_button::Entity),
Config(Config), Config(Config),
Copy(Option<segmented_button::Entity>), Copy(Option<segmented_button::Entity>),
CopyPrimary(Option<segmented_button::Entity>),
DefaultBoldFontWeight(usize), DefaultBoldFontWeight(usize),
DefaultDimFontWeight(usize), DefaultDimFontWeight(usize),
DefaultFont(usize), DefaultFont(usize),
@ -275,6 +281,7 @@ pub enum Message {
FindNext, FindNext,
FindPrevious, FindPrevious,
FindSearchValueChanged(String), FindSearchValueChanged(String),
MiddleClick(pane_grid::Pane, Option<segmented_button::Entity>),
FocusFollowMouse(bool), FocusFollowMouse(bool),
Key(Modifiers, Key), Key(Modifiers, Key),
LaunchUrl(String), LaunchUrl(String),
@ -288,6 +295,7 @@ pub enum Message {
PaneSplit(pane_grid::Axis), PaneSplit(pane_grid::Axis),
PaneToggleMaximized, PaneToggleMaximized,
Paste(Option<segmented_button::Entity>), Paste(Option<segmented_button::Entity>),
PastePrimary(Option<segmented_button::Entity>),
PasteValue(Option<segmented_button::Entity>, String), PasteValue(Option<segmented_button::Entity>, String),
ProfileCollapse(ProfileId), ProfileCollapse(ProfileId),
ProfileCommand(ProfileId, String), ProfileCommand(ProfileId, String),
@ -1679,6 +1687,20 @@ impl Application for App {
} }
return self.update_focus(); return self.update_focus();
} }
Message::CopyPrimary(entity_opt) => {
if let Some(tab_model) = self.pane_model.active() {
let entity = entity_opt.unwrap_or_else(|| tab_model.active());
if let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity) {
let terminal = terminal.lock().unwrap();
let term = terminal.term.lock();
if let Some(text) = term.selection_to_string() {
return Command::batch([clipboard::write_primary(text), self.update_focus()]);
}
}
} else {
log::warn!("Failed to get focused pane");
}
}
Message::DefaultFont(index) => { Message::DefaultFont(index) => {
match self.font_names.get(index) { match self.font_names.get(index) {
Some(font_name) => { Some(font_name) => {
@ -1827,6 +1849,16 @@ impl Application for App {
Message::FindSearchValueChanged(value) => { Message::FindSearchValueChanged(value) => {
self.find_search_value = value; self.find_search_value = value;
} }
Message::MiddleClick(pane, entity_opt) => {
self.pane_model.focus = pane;
return Command::batch([
self.update_focus(),
clipboard::read_primary(move |value_opt| match value_opt {
Some(value) => message::app(Message::PasteValue(entity_opt, value)),
None => message::none(),
}),
]);
}
Message::FocusFollowMouse(focus_follow_mouse) => { Message::FocusFollowMouse(focus_follow_mouse) => {
config_set!(focus_follow_mouse, focus_follow_mouse); config_set!(focus_follow_mouse, focus_follow_mouse);
} }
@ -1902,6 +1934,12 @@ impl Application for App {
None => message::none(), None => message::none(),
}); });
} }
Message::PastePrimary(entity_opt) => {
return clipboard::read_primary(move |value_opt| match value_opt {
Some(value) => message::app(Message::PasteValue(entity_opt, value)),
None => message::none(),
});
}
Message::PasteValue(entity_opt, value) => { Message::PasteValue(entity_opt, value) => {
if let Some(tab_model) = self.pane_model.active() { if let Some(tab_model) = self.pane_model.active() {
let entity = entity_opt.unwrap_or_else(|| tab_model.active()); let entity = entity_opt.unwrap_or_else(|| tab_model.active());
@ -2444,6 +2482,7 @@ impl Application for App {
} }
let entity = tab_model.active(); let entity = tab_model.active();
let entity_middle_click = tab_model.active();
let terminal_id = self let terminal_id = self
.terminal_ids .terminal_ids
.get(&pane) .get(&pane)
@ -2456,6 +2495,9 @@ impl Application for App {
.on_context_menu(move |position_opt| { .on_context_menu(move |position_opt| {
Message::TabContextMenu(pane, position_opt) Message::TabContextMenu(pane, position_opt)
}) })
.on_middle_click(move || {
Message::MiddleClick(pane, Some(entity_middle_click))
})
.opacity(self.config.opacity_ratio()) .opacity(self.config.opacity_ratio())
.padding(space_xxs); .padding(space_xxs);
@ -2566,6 +2608,9 @@ impl Application for App {
Event::Keyboard(KeyEvent::ModifiersChanged(modifiers)) => { Event::Keyboard(KeyEvent::ModifiersChanged(modifiers)) => {
Some(Message::Modifiers(modifiers)) Some(Message::Modifiers(modifiers))
} }
Event::Mouse(MouseEvent::ButtonReleased(MouseButton::Left)) => {
Some(Message::CopyPrimary(None))
}
_ => None, _ => None,
}), }),
subscription::channel( subscription::channel(

View file

@ -54,6 +54,7 @@ pub struct TerminalBox<'a, Message> {
on_mouse_enter: Option<Box<dyn Fn() -> Message + 'a>>, on_mouse_enter: Option<Box<dyn Fn() -> Message + 'a>>,
opacity: Option<f32>, opacity: Option<f32>,
mouse_inside_boundary: Option<bool>, mouse_inside_boundary: Option<bool>,
on_middle_click: Option<Box<dyn Fn() -> Message + 'a>>,
key_binds: HashMap<KeyBind, Action>, key_binds: HashMap<KeyBind, Action>,
} }
@ -73,6 +74,7 @@ where
on_mouse_enter: None, on_mouse_enter: None,
opacity: None, opacity: None,
mouse_inside_boundary: None, mouse_inside_boundary: None,
on_middle_click: None,
key_binds: key_binds(), key_binds: key_binds(),
} }
} }
@ -115,6 +117,11 @@ where
self self
} }
pub fn on_middle_click(mut self, on_middle_click: impl Fn() -> Message + 'a) -> Self {
self.on_middle_click = Some(Box::new(on_middle_click));
self
}
pub fn opacity(mut self, opacity: f32) -> Self { pub fn opacity(mut self, opacity: f32) -> Self {
self.opacity = Some(opacity); self.opacity = Some(opacity);
self self
@ -897,6 +904,10 @@ where
} }
} }
} }
} else if button == Button::Middle {
if let Some(on_middle_click) = &self.on_middle_click {
shell.publish(on_middle_click());
}
} }
// Update context menu state // Update context menu state
if let Some(on_context_menu) = &self.on_context_menu { if let Some(on_context_menu) = &self.on_context_menu {