diff options
| author | Tom Dalziel <tom_dl@hotmail.com> | 2024-03-30 23:17:58 +0100 |
|---|---|---|
| committer | Tom Dalziel <33435574+tomdl89@users.noreply.github.com> | 2024-03-31 00:39:27 +0100 |
| commit | 643e01d1a07fc472b5a9ff6fa3ec001ddc8681ba (patch) | |
| tree | 8d857063a99ca272a9d5952c0941177fa08c2fa4 | |
| parent | 700d574843e2ae3545c983dcf6ad6db604d38c43 (diff) | |
Add handler for expanding line for line-based operators
Most of the work was done by Maxi Wolff (@smile13241324) over 6yrs ago.
I've made a few changes, so have assumed authorship.
This fixes #968
| -rw-r--r-- | evil-commands.el | 68 | ||||
| -rw-r--r-- | evil-tests.el | 37 |
2 files changed, 74 insertions, 31 deletions
diff --git a/evil-commands.el b/evil-commands.el index 62a6597..2ae01d5 100644 --- a/evil-commands.el +++ b/evil-commands.el @@ -1436,23 +1436,37 @@ the left edge." (evil-yank-characters beg end register yank-handler) (goto-char beg))))) -(evil-define-operator evil-yank-line (beg end type register) - "Save whole lines into the kill-ring." - :motion evil-line-or-visual-line - :move-point nil - (interactive "<R><x>") +(defun evil-expand-line-for-line-based-operators (beg end type) + "Expand to line when in visual mode possibly changing BEG, END and TYPE. +Avoids double expansion for line based commands like 'V' or 'D'." (when (evil-visual-state-p) (unless (memq type '(line block screen-line)) - (let ((range (evil-expand beg end - (if (and evil-respect-visual-line-mode - visual-line-mode) - 'screen-line - 'line)))) + ;; Subtract 1 from end to avoid expanding to the next line + ;; when \n is part of the visually selected region. + ;; If removed (evil-expand beg end 'line) + ;; will expand to the end of the next line instead of the current + ;; line which will cause line expanding commands like 'Y' to + ;; misbehave when used in visual state. + (when (eq ?\n (char-before end)) + (cl-decf end)) + (let ((range (evil-expand beg end (if (and evil-respect-visual-line-mode + visual-line-mode) + 'screen-line + 'line)))) (setq beg (evil-range-beginning range) end (evil-range-end range) type (evil-type range)))) (evil-exit-visual-state)) - (evil-yank beg end type register)) + (list beg end type)) + +(evil-define-operator evil-yank-line (beg end type register) + "Save whole lines into the kill-ring." + :motion evil-line-or-visual-line + :move-point nil + (interactive "<R><x>") + (cl-destructuring-bind + (beg end type) (evil-expand-line-for-line-based-operators beg end type) + (evil-yank beg end type register))) (evil-define-operator evil-delete (beg end type register yank-handler) "Delete text from BEG to END with TYPE. @@ -1502,24 +1516,17 @@ Save in REGISTER or in the kill-ring with YANK-HANDLER." "Delete to end of line." :motion evil-end-of-line-or-visual-line (interactive "<R><x>") - ;; Act linewise in Visual state - (when (and (evil-visual-state-p) (eq type 'inclusive)) - (let ((range (evil-expand - beg end - (if (and evil-respect-visual-line-mode visual-line-mode) - 'screen-line 'line)))) - (setq beg (car range) - end (cadr range) - type (evil-type range)))) - (if (eq type 'block) - ;; Equivalent to $d, i.e., we use the block-to-eol selection and - ;; call `evil-delete'. In this case we fake the call to - ;; `evil-end-of-line' by setting `temporary-goal-column' and - ;; `last-command' appropriately as `evil-end-of-line' would do. - (let ((temporary-goal-column most-positive-fixnum) - (last-command 'next-line)) - (evil-delete beg end 'block register yank-handler)) - (evil-delete beg end type register yank-handler))) + (cl-destructuring-bind + (beg end type) (evil-expand-line-for-line-based-operators beg end type) + (if (eq type 'block) + ;; Equivalent to $d, i.e., we use the block-to-eol selection and + ;; call `evil-delete'. In this case we fake the call to + ;; `evil-end-of-line' by setting `temporary-goal-column' and + ;; `last-command' appropriately as `evil-end-of-line' would do. + (let ((temporary-goal-column most-positive-fixnum) + (last-command 'next-line)) + (evil-delete beg end 'block register yank-handler)) + (evil-delete beg end type register yank-handler)))) (evil-define-operator evil-delete-whole-line (beg end type register yank-handler) @@ -1672,7 +1679,8 @@ of the block." :motion evil-end-of-line-or-visual-line (interactive "<R><x><y>") (if (and (evil-visual-state-p) (eq type 'inclusive)) - (cl-destructuring-bind (beg end &rest) (evil-line-expand beg end) + (cl-destructuring-bind + (beg end _type) (evil-expand-line-for-line-based-operators beg end type) (evil-change-whole-line beg end register yank-handler)) (evil-change beg end type register yank-handler #'evil-delete-line))) diff --git a/evil-tests.el b/evil-tests.el index 8004633..b474770 100644 --- a/evil-tests.el +++ b/evil-tests.el @@ -2013,6 +2013,20 @@ New Tex[t] ("my" "G" ":'y,.y") "1\n2\n3\n4\n5\n6\n7\n8\n9\n[1]0"))) +(ert-deftest evil-test-yank-line () + "Test `evil-yank-line'" + :tags '(evil operator) + (ert-info ("Yank line with eof being part of visual selection") + (evil-test-buffer + ";; This is line one +;; This is lin[e] two +;; This is line three" + ("v$Yjp") + ";; This is line one +;; This is line two +;; This is line three +[;]; This is line two"))) + (ert-deftest evil-test-delete () "Test `evil-delete'" :tags '(evil operator delete) @@ -2144,7 +2158,15 @@ ine3 line3 line3 l\n")) (evil-test-buffer "a[a]a\nbbb\nc\n" ("2D") - "a\nc\n"))) + "a\nc\n")) + (ert-info ("Delete line with eof being part of visual selection") + (evil-test-buffer + ";; This is line one +;; This is lin[e] two +;; This is line three" + ("v$D") + ";; This is line one +;; This is line three"))) (ert-deftest evil-test-delete-folded () "Test `evil-delete' on folded lines." @@ -2342,6 +2364,19 @@ ABCthen enter the text in that file's own buffer."))) [] five"))) +(ert-deftest evil-test-change-line () + "Test `evil-change-line'" + :tags '(evil operator) + (ert-info ("Change line with eof being part of visual selection") + (evil-test-buffer + "This is line one +This is lin[e] two +This is line three" + ("v$C") + "This is line one +[] +This is line three"))) + (ert-deftest evil-test-change-word () "Test changing words" :tags '(evil operator) |
