;;; system.el --- System integration functions -*- lexical-binding: t; -*- (defun my/system-cut (beg end) "Cut region directly to system clipboard, bypassing the kill ring." (interactive "r") (my/system-copy beg end) ;; delete-region deletes without adding to the kill ring (delete-region beg end)) (defun my/system-copy (beg end) "Pure copy: Sends the active region directly to the system clipboard. Absolutely zero interaction with the Emacs kill ring." (interactive "r") (unless (region-active-p) (user-error "No active region to copy")) (let ((text (buffer-substring-no-properties beg end))) (if (display-graphic-p) ;; Low-level GUI primitive: talks directly to the OS clipboard manager (gui-backend-set-selection 'CLIPBOARD text) ;; TUI Fallback via Clipetty (if (fboundp 'clipetty-set-selection) (clipetty-set-selection text) (error "Clipetty not loaded"))) (deactivate-mark) (message "Copied to system clipboard (pure)"))) (defun my/system-paste () "Pure paste: Inserts text directly from the system clipboard. Never falls back to or checks the Emacs kill ring." (interactive) (if (display-graphic-p) (let ((text (or (gui-get-selection 'CLIPBOARD) (gui-get-selection 'PRIMARY) (when (executable-find "wl-paste") (let ((val (shell-command-to-string "wl-paste -n -t text/plain"))) (unless (string-empty-p val) val)))))) (if text (insert text) (user-error "System clipboard is empty"))) ;; TUI Fallback (message "In a terminal, use your terminal emulator's native paste shortcut (e.g., Ctrl-Shift-V)."))) (defun my/system-paste-via-yank () "Pure paste: Overwrites the kill ring with clipboard data and triggers local yank." (interactive) (let ((text (or (gui-get-selection 'CLIPBOARD) (gui-get-selection 'PRIMARY) (when (executable-find "wl-paste") (when (executable-find "wl-paste") (let ((val (shell-command-to-string "wl-paste -n -t text/plain"))) (unless (string-empty-p val) val)))) nil))) (if text (progn ;; Forcibly stage to the kill ring. With kill-ring-max=1, this replaces everything. (kill-new text) ;; Resolve the context-aware yank command (handles terminal wrappers automatically) (let ((local-yank (key-binding (kbd "C-y")))) (if (commandp local-yank) (call-interactively local-yank) (call-interactively 'yank)))) (user-error "System clipboard is empty")))) (defun my/sync-clipboard-to-kill-ring () "Explicitly pull the system clipboard into the Emacs kill ring without pasting." (interactive) (let ((text (or (gui-get-selection 'CLIPBOARD) (gui-get-selection 'PRIMARY) (when (executable-find "wl-paste") (when (executable-find "wl-paste") (let ((val (shell-command-to-string "wl-paste -n -t text/plain"))) (unless (string-empty-p val) val)))) nil))) (if text (progn (kill-new text) (message "System clipboard staged to kill ring.")) (user-error "System clipboard is empty")))) (defun dired-wayland-copy-marked-files () "Copy marked files in Dired to the Wayland clipboard as text/uri-list." (interactive) (let* ((files (dired-get-marked-files)) ;; Convert paths to file:// URIs and join with newlines (uri-list (mapconcat (lambda (file) (concat "file://" file)) files "\n"))) (when files (let ((process-connection-type nil)) (let ((proc (start-process "wl-copy-uri" nil "wl-copy" "-t" "text/uri-list"))) (process-send-string proc uri-list) (process-send-eof proc))) (message "Copied %d file(s) to Wayland clipboard." (length files))))) (defun dired-wayland-paste-files () "Paste files from the Wayland clipboard (text/uri-list) into the current Dired directory." (interactive) (let ((default-directory (dired-current-directory))) (with-temp-buffer ;; Call wl-paste to get the uri-list (call-process "wl-paste" nil t nil "-t" "text/uri-list") (goto-char (point-min)) (let ((files '())) ;; Parse file:// URIs line by line (while (re-search-forward "^file://\\(.*\\)$" nil t) (push (match-string 1) files)) (if files (progn ;; Copy files to the current directory using dired's native copying (dolist (file files) (when (file-exists-p file) (dired-copy-file file default-directory t))) (revert-buffer) ; Refresh dired buffer (message "Pasted %d file(s)." (length files))) (message "No files found in Wayland clipboard.")))))) ;; Bind keys in dired-mode (with-eval-after-load 'dired (define-key dired-mode-map (kbd "Y") #'dired-wayland-copy-marked-files) (define-key dired-mode-map (kbd "P") #'dired-wayland-paste-files)) (defun my/mc-copy-regions-as-block () "Copy all active multiple-cursors regions joined by newlines into the kill ring." (interactive) (if (and (bound-and-true-p multiple-cursors-mode) (use-region-p)) (let ((strings (mapcar (lambda (cursor) (let ((beg (mc/cursor-beg cursor)) (end (mc/cursor-end cursor))) (buffer-substring-no-properties beg end))) (mc/all-fake-cursors)))) ;; Add the main cursor's region as well (push (buffer-substring-no-properties (region-beginning) (region-end)) strings) ;; Sort by position so they match document order (setq strings (mapcar #'cdr (sort (cl-mapcar #'cons (cons (point) (mapcar #'mc/cursor-beg (mc/all-fake-cursors))) strings) (lambda (a b) (< (car a) (car b)))))) (kill-new (string-join strings "\n")) (message "Copied %d cursor regions as a block." (length strings))) (message "No active multiple-cursors regions to copy."))) (provide 'system)