yoda: copie a la selection vers le presse-papiers, a la Ghostty

La selection n'allait que dans la selection primaire (clic du milieu) ;
pour la coller avec Ctrl+V ailleurs, il fallait Ctrl+Shift+C. Reprise de
copy-on-select = clipboard de Ghostty, le reglage de l'ancienne config
Ghostty de Lionel.

- Config copy_on_select_clipboard (desactive par defaut, comme l'amont) ;
  case dans Reglages > Avance.
- terminal_box::on_selection_done : publie a la fin d'un geste de
  selection fait dans le panneau (glisser, double/triple clic, Shift+
  clic), pas a chaque relachement du bouton gauche. La copie primaire
  existante part elle a tout relachement dans la fenetre : la recopier
  dans le presse-papiers ecraserait, au simple clic sur un onglet, ce
  qu'on vient de copier ailleurs avec une vieille selection.
- Message::SelectionDone : copie la selection de cet onglet ; une
  selection vide (simple clic) ne donne pas de texte (range_simple).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Lionel DARNIS 2026-10-01 14:38:17 +02:00
parent a035b47e98
commit 9b10e98ab1
5 changed files with 56 additions and 0 deletions

View file

@ -68,6 +68,8 @@ window-header = Window header
show-header-description = Reveal the header from the right-click menu
tab-new-inherit-working-directory = New tabs and windows use current directory
tab-new-inherit-working-directory-description = Open new tabs and windows in the active tab's working directory
copy-on-select-clipboard = Copy selection to clipboard
copy-on-select-clipboard-description = In addition to the primary selection (middle click), like copy-on-select = clipboard in Ghostty
### Keyboard shortcuts
add-another-keybinding = Add another keybinding

View file

@ -172,5 +172,7 @@ comment = Émulateur de terminal pour le bureau COSMIC
keywords = Commande;Shell;Terminal;CLI;
tab-new-inherit-working-directory = Les nouveaux onglets et fenêtres utilisent le répertoire actuel
tab-new-inherit-working-directory-description = Ouvrir les nouveaux onglets et fenêtres dans le répertoire de travail de l'onglet actif
copy-on-select-clipboard = Copier la sélection dans le presse-papiers
copy-on-select-clipboard-description = En plus de la sélection primaire (clic du milieu), comme copy-on-select = clipboard dans Ghostty
show-pane-borders = Afficher les bordures des panneaux
unfocused-pane-dim = Atténuation des panneaux inactifs

View file

@ -242,6 +242,11 @@ pub struct Config {
pub focus_follow_mouse: bool,
#[serde(default)]
pub tab_new_inherit_working_directory: bool,
/// [yoda] Copier aussi la sélection dans le presse-papiers, et pas
/// seulement dans la sélection primaire (`copy-on-select = clipboard` de
/// Ghostty).
#[serde(default)]
pub copy_on_select_clipboard: bool,
pub default_profile: Option<ProfileId>,
#[serde(default)]
pub shortcuts_custom: Shortcuts,
@ -264,6 +269,7 @@ impl Default for Config {
dim_font_weight: Weight::NORMAL.0,
focus_follow_mouse: false,
tab_new_inherit_working_directory: false,
copy_on_select_clipboard: false,
font_name: "Noto Sans Mono".to_string(),
font_size: 14,
font_size_zoom_step_mul_100: 100,

View file

@ -600,6 +600,8 @@ pub enum Message {
SyntaxTheme(ColorSchemeKind, usize),
SystemThemeChange,
TabNewInheritWorkingDirectory(bool),
CopyOnSelectClipboard(bool),
SelectionDone(pane_grid::Pane, segmented_button::Entity),
TabActivate(segmented_button::Entity),
TabActivateJump(usize),
TabClose(Option<segmented_button::Entity>),
@ -1759,6 +1761,14 @@ impl App {
self.config.tab_new_inherit_working_directory,
Message::TabNewInheritWorkingDirectory,
),
)
.add(
widget::settings::item::builder(fl!("copy-on-select-clipboard"))
.description(fl!("copy-on-select-clipboard-description"))
.toggler(
self.config.copy_on_select_clipboard,
Message::CopyOnSelectClipboard,
),
);
widget::settings::view_column(vec![
@ -3404,6 +3414,24 @@ impl Application for App {
return self.update_config();
}
}
Message::CopyOnSelectClipboard(copy_on_select_clipboard) => {
if copy_on_select_clipboard != self.config.copy_on_select_clipboard {
config_set!(copy_on_select_clipboard, copy_on_select_clipboard);
}
}
Message::SelectionDone(pane, entity) => {
// [yoda] Copie à la sélection vers le presse-papiers ; la
// sélection primaire, elle, suit le relâchement du bouton.
if self.config.copy_on_select_clipboard
&& let Some(tab_model) = self.pane_model.panes.get(pane)
&& let Some(terminal) = tab_model.data::<Mutex<Terminal>>(entity)
{
let text = terminal.lock().unwrap().term.lock().selection_to_string();
if let Some(text) = text.filter(|text| !text.is_empty()) {
return clipboard::write(text);
}
}
}
Message::TabNewInheritWorkingDirectory(tab_new_inherit_working_directory) => {
config_set!(
tab_new_inherit_working_directory,
@ -4298,6 +4326,11 @@ impl Application for App {
terminal_box = terminal_box.on_mouse_enter(move || Message::MouseEnter(pane));
}
if self.config.copy_on_select_clipboard {
terminal_box =
terminal_box.on_selection_done(move || Message::SelectionDone(pane, entity));
}
// [yoda] Voile sur les panneaux non focalisés (à la Ghostty), seulement
// quand il y en a plusieurs : on voit d'un coup d'œil où l'on tape.
if let Some(dim) = self.config.unfocused_pane_dim_ratio()

View file

@ -123,6 +123,7 @@ pub struct TerminalBox<'a, Message> {
dim: Option<f32>,
mouse_inside_boundary: Option<bool>,
on_middle_click: Option<Box<dyn Fn() -> Message + 'a>>,
on_selection_done: Option<Box<dyn Fn() -> Message + 'a>>,
on_open_hyperlink: Option<Box<dyn Fn(String) -> Message + 'a>>,
on_window_focused: Option<Box<dyn Fn() -> Message + 'a>>,
on_window_unfocused: Option<Box<dyn Fn() -> Message + 'a>>,
@ -151,6 +152,7 @@ where
dim: None,
mouse_inside_boundary: None,
on_middle_click: None,
on_selection_done: None,
key_binds,
on_open_hyperlink: None,
on_window_focused: None,
@ -208,6 +210,14 @@ where
self
}
/// [yoda] Fin d'un geste de sélection fait dans ce panneau (glisser, double
/// ou triple clic, Shift+clic) : le moment de copier la sélection. Un
/// simple clic ailleurs dans la fenêtre ne le déclenche pas.
pub fn on_selection_done(mut self, on_selection_done: impl Fn() -> Message + 'a) -> Self {
self.on_selection_done = Some(Box::new(on_selection_done));
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
@ -1581,6 +1591,9 @@ where
}
}
terminal.needs_update = true;
if let Some(on_selection_done) = &self.on_selection_done {
shell.publish(on_selection_done());
}
}
if let Some(p) = cursor_position.position_in(layout.bounds()) {
let x = p.x - self.padding.left;