From 981331cfe0757b21f529be02d848a3ef7bcc4295 Mon Sep 17 00:00:00 2001 From: Philip Kaludercic Date: Tue, 3 Sep 2024 18:29:56 +0200 Subject: [PATCH] Allow 'kill-region' kill the last word when there is no region * etc/NEWS: Document the new user option. * lisp/simple.el (kill-region-dwim): Add new option. (kill-region): Respect 'kill-region-dwim'. (Bug#69097) --- etc/NEWS | 6 ++++++ lisp/simple.el | 50 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 48 insertions(+), 8 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index 1e66f084117..7fadf52a6cf 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -123,6 +123,12 @@ When using 'visual-wrap-prefix-mode' in buffers with variable-pitch fonts, the wrapped text will now be lined up correctly so that it's exactly below the text after the prefix on the first line. +--- +** New user option 'kill-word-if-no-region'. +This option will modify the fall-back behaviour of 'kill-region' if no +region is active, and will kill the last word instead of raising an +error. + * Changes in Specialized Modes and Packages in Emacs 31.1 diff --git a/lisp/simple.el b/lisp/simple.el index eedc5768fe2..3b4453c7a8f 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -5817,6 +5817,17 @@ kill-read-only-ok :type 'boolean :group 'killing) +(defcustom kill-region-dwim nil + "Behaviour when `kill-region' is invoked without an active region. +If set to nil (default), then an error occurs and nothing is killed. If +set to `emacs-word', then kill a the last word as defined by the current +major mode. If set to `unix-word', then kill the last word in the style +of a shell like Bash, disregarding the major mode." + :type '(choice (const :tag "Kill a word like `backward-kill-word'" emacs-word) + (const :tag "Kill a word like Bash would" unix-word) + (const :tag "Do not kill anything" nil)) + :group 'killing) + (defun kill-region (beg end &optional region) "Kill (\"cut\") text between point and mark. This deletes the text from the buffer and saves it in the kill ring. @@ -5843,21 +5854,44 @@ kill-region (To delete text, use `delete-region'.) Supply two arguments, character positions BEG and END indicating the stretch of text to be killed. If the optional argument REGION is - non-nil, the function ignores BEG and END, and kills the current + `region', the function ignores BEG and END, and kills the current region instead. Interactively, REGION is always non-nil, and so - this command always kills the current region." + this command always kills the current region. It is possible to + override this behaviour by customising the user option + `kill-region-dwim'." ;; Pass mark first, then point, because the order matters when ;; calling `kill-append'. (interactive (progn (let ((beg (mark)) (end (point))) - (unless (and beg end) - (user-error "The mark is not set now, so there is no region")) - (list beg end 'region)))) + (cond + ((and beg end (use-region-p)) + (list beg end 'region)) + (kill-region-dwim + (list beg end kill-region-dwim)) + ((user-error "The mark is not set now, so there is no region")))))) + (condition-case nil - (let ((string (if region - (funcall region-extract-function 'delete) - (filter-buffer-substring beg end 'delete)))) + (let ((string (cond + ((eq region 'emacs-word) + (let ((end (point))) + (save-excursion + (forward-word -1) + (filter-buffer-substring (point) end 'delete)))) + ((eq region 'unix-word) + (let ((end (point))) + (save-excursion + (skip-chars-backward "[:space:]") + (skip-chars-backward "^[:space:]") + (filter-buffer-substring + (if (get-char-property (point) 'read-only) + (next-single-char-property-change + (point) 'read-only nil end) + (point)) + end 'delete)))) + (region + (funcall region-extract-function 'delete)) + ((filter-buffer-substring beg end 'delete))))) (when string ;STRING is nil if BEG = END ;; Add that string to the kill ring, one way or another. (if (eq last-command 'kill-region) -- 2.46.0