diff --git a/lisp/simple.el b/lisp/simple.el index eedc5768fe2..9ce108089e7 100644 --- a/lisp/simple.el +++ b/lisp/simple.el @@ -5817,6 +5817,17 @@ kill-read-only-ok :type 'boolean :group 'killing) +(defcustom kill-word-if-no-region 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. @@ -5839,25 +5850,47 @@ kill-region the text, but put the text in the kill ring anyway. This means that you can use the killing commands to copy text from a read-only buffer. -Lisp programs should use this function for killing text. - (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 instead. Interactively, REGION is always non-nil, and so - this command always kills the current region." +Lisp programs should use this function for killing text. (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 instead. If REGION has the special value +`kill-word', then it will kill the previous word, as with +`backward-kill-word'. Interactively, REGION is always non-nil, and so +this command always kills the current region." ;; 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-word-if-no-region + (list beg end kill-word-if-no-region)) + ((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)