From 0f19dadb75a01873cb3f40a6addd825e63c266ce 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 | 7 +++++++ lisp/simple.el | 41 ++++++++++++++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 7 deletions(-) diff --git a/etc/NEWS b/etc/NEWS index add438e8b6a..8cde2c294a9 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -129,6 +129,13 @@ Unix-words are words separated by whitespace regardless of the buffer's syntax table. In a Unix terminal or shell, C-w kills by Unix-word. The new commands 'unix-word-rubout' and 'unix-filename-rubout' allow you to bind keys to operate more similarly to the terminal. + +--- +** New user option 'kill-word-dwim'. +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 bbb13c1b471..d1be33ce87d 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -5817,6 +5817,19 @@ 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), the behaviour of `kill-region' stays the same. +If set to `emacs-word', then kill 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 like with +`unix-word-rubout'." + :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 + :version "31.1") + (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 +5856,35 @@ 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) + (cond + ((and kill-region-dwim (not (use-region-p))) + (list beg end kill-region-dwim)) + ((not (or beg end)) (user-error "The mark is not set now, so there is no region")) - (list beg end 'region)))) + ((list beg end 'region)))))) + (condition-case nil - (let ((string (if region - (funcall region-extract-function 'delete) - (filter-buffer-substring beg end 'delete)))) + (let ((string (cond + ((memq region '(unix-word emacs-word)) + (let ((end (point))) + (save-excursion + (if (eq region 'emacs-word) + (forward-word -1) + (forward-unix-word -1)) + (filter-buffer-substring (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.45.2