A new option to clear selections when they no longer reflect the contents of the clipboard

This commit is contained in:
Kovid Goyal
2025-03-12 11:41:27 +05:30
parent b34a88065b
commit 96d5c9c7c6
7 changed files with 37 additions and 1 deletions

View File

@@ -99,6 +99,8 @@ Detailed list of changes
- Do not count background processes by default for :opt:`confirm_os_window_close` (:iss:`8358`)
- A new option :opt:`clear_selection_on_clipboard_loss` to clear selections when they no longer reflect the contents of the clipboard
- Fix flickering of hyperlink underline when client program continuously
redraws on mouse movement (:iss:`8414`)

View File

@@ -296,8 +296,10 @@ def linenum_handle_result(args: list[str], data: dict[str, Any], target_window_i
w.paste_bytes(text)
elif program == '@':
set_clipboard_string(text)
boss.handle_clipboard_loss('clipboard')
elif program == '*':
set_primary_selection(text)
boss.handle_clipboard_loss('primary')
elif program.startswith('@'):
boss.set_clipboard_buffer(program[1:], text)
else:

View File

@@ -2243,6 +2243,7 @@ class Boss:
text = w.text_for_selection()
if text:
set_primary_selection(text)
self.handle_clipboard_loss('primary', w.id)
if get_options().copy_on_select:
self.copy_to_buffer(get_options().copy_on_select)
@@ -2280,8 +2281,10 @@ class Boss:
if text:
if buffer_name == 'clipboard':
set_clipboard_string(text)
self.handle_clipboard_loss('clipboard', w.id)
elif buffer_name == 'primary':
set_primary_selection(text)
self.handle_clipboard_loss('primary', w.id)
else:
self.set_clipboard_buffer(buffer_name, text)
@@ -2508,8 +2511,10 @@ class Boss:
if stdin:
if dest == 'clipboard':
set_clipboard_string(stdin)
self.handle_clipboard_loss('clipboard')
else:
set_primary_selection(stdin)
self.handle_clipboard_loss('primary')
else:
env, stdin = self.process_stdin_source(stdin=source, window=window)
self.run_background_process(cmd, cwd_from=cwd_from, stdin=stdin, env=env)
@@ -3062,6 +3067,7 @@ class Boss:
if w is not None:
output = debug_config(get_options(), self.mappings.global_shortcuts)
set_clipboard_string(re.sub(r'\x1b.+?m', '', output))
self.handle_clipboard_loss('clipboard')
output += '\n\x1b[35mThis debug output has been copied to the clipboard\x1b[m' # ]]]
self.display_scrollback(w, output, title=_('Current kitty options'), report_cursor=False)
@@ -3112,4 +3118,12 @@ class Boss:
cocoa_show_progress_bar_on_dock_icon()
def on_clipboard_lost(self, which: Literal['clipboard', 'primary']) -> None:
pass
self.handle_clipboard_loss(which)
def handle_clipboard_loss(self, which: Literal['clipboard', 'primary'], exception: int = 0) -> None:
opts = get_options()
if opts.clear_selection_on_clipboard_loss and (which == 'primary' or opts.copy_on_select == 'clipboard'):
for wid, window in self.window_id_map.items():
if wid == exception:
continue
window.screen.clear_selection()

View File

@@ -709,8 +709,10 @@ def _launch(
if stdin is not None:
if opts.type == 'clipboard':
set_clipboard_string(stdin)
boss.handle_clipboard_loss('clipboard')
else:
set_primary_selection(stdin)
boss.handle_clipboard_loss('primary')
else:
kw['hold'] = opts.hold
if force_target_tab and target_tab is not None:

View File

@@ -603,6 +603,17 @@ clipboard.
'''
)
opt('clear_selection_on_clipboard_loss', 'no', option_type='to_bool', long_text='''
When the contents of the clipboard no longer reflect the current selection, clear it.
This is primarily useful on platforms such as Linux where selecting text automatically
copies it to a special "primary selection" clipboard or if you have :opt:`copy_on_select`
set to :code:`clipboard`.
Note that on macOS the system does not provide notifications when the clipboard owner
is changed, so there, copying to clipboard in a non-kitty application will not clear
selections even if :opt:`copy_on_select` is enabled.
''')
opt('paste_actions', 'quote-urls-at-prompt,confirm',
option_type='paste_actions',
long_text='''

View File

@@ -119,6 +119,9 @@ class Parser:
def clear_all_shortcuts(self, val: str, ans: dict[str, typing.Any]) -> None:
clear_all_shortcuts(val, ans)
def clear_selection_on_clipboard_loss(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['clear_selection_on_clipboard_loss'] = to_bool(val)
def click_interval(self, val: str, ans: dict[str, typing.Any]) -> None:
ans['click_interval'] = float(val)

View File

@@ -63,6 +63,7 @@ option_names = (
'box_drawing_scale',
'clear_all_mouse_actions',
'clear_all_shortcuts',
'clear_selection_on_clipboard_loss',
'click_interval',
'clipboard_control',
'clipboard_max_size',
@@ -500,6 +501,7 @@ class Options:
box_drawing_scale: tuple[float, float, float, float] = (0.001, 1.0, 1.5, 2.0)
clear_all_mouse_actions: bool = False
clear_all_shortcuts: bool = False
clear_selection_on_clipboard_loss: bool = False
click_interval: float = -1.0
clipboard_control: tuple[str, ...] = ('write-clipboard', 'write-primary', 'read-clipboard-ask', 'read-primary-ask')
clipboard_max_size: float = 512.0