Skip to content

Commit 643e01d

Browse files
committed
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
1 parent 700d574 commit 643e01d

File tree

2 files changed

+74
-31
lines changed

2 files changed

+74
-31
lines changed

evil-commands.el

Lines changed: 38 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1436,23 +1436,37 @@ the left edge."
14361436
(evil-yank-characters beg end register yank-handler)
14371437
(goto-char beg)))))
14381438

1439-
(evil-define-operator evil-yank-line (beg end type register)
1440-
"Save whole lines into the kill-ring."
1441-
:motion evil-line-or-visual-line
1442-
:move-point nil
1443-
(interactive "<R><x>")
1439+
(defun evil-expand-line-for-line-based-operators (beg end type)
1440+
"Expand to line when in visual mode possibly changing BEG, END and TYPE.
1441+
Avoids double expansion for line based commands like 'V' or 'D'."
14441442
(when (evil-visual-state-p)
14451443
(unless (memq type '(line block screen-line))
1446-
(let ((range (evil-expand beg end
1447-
(if (and evil-respect-visual-line-mode
1448-
visual-line-mode)
1449-
'screen-line
1450-
'line))))
1444+
;; Subtract 1 from end to avoid expanding to the next line
1445+
;; when \n is part of the visually selected region.
1446+
;; If removed (evil-expand beg end 'line)
1447+
;; will expand to the end of the next line instead of the current
1448+
;; line which will cause line expanding commands like 'Y' to
1449+
;; misbehave when used in visual state.
1450+
(when (eq ?\n (char-before end))
1451+
(cl-decf end))
1452+
(let ((range (evil-expand beg end (if (and evil-respect-visual-line-mode
1453+
visual-line-mode)
1454+
'screen-line
1455+
'line))))
14511456
(setq beg (evil-range-beginning range)
14521457
end (evil-range-end range)
14531458
type (evil-type range))))
14541459
(evil-exit-visual-state))
1455-
(evil-yank beg end type register))
1460+
(list beg end type))
1461+
1462+
(evil-define-operator evil-yank-line (beg end type register)
1463+
"Save whole lines into the kill-ring."
1464+
:motion evil-line-or-visual-line
1465+
:move-point nil
1466+
(interactive "<R><x>")
1467+
(cl-destructuring-bind
1468+
(beg end type) (evil-expand-line-for-line-based-operators beg end type)
1469+
(evil-yank beg end type register)))
14561470

14571471
(evil-define-operator evil-delete (beg end type register yank-handler)
14581472
"Delete text from BEG to END with TYPE.
@@ -1502,24 +1516,17 @@ Save in REGISTER or in the kill-ring with YANK-HANDLER."
15021516
"Delete to end of line."
15031517
:motion evil-end-of-line-or-visual-line
15041518
(interactive "<R><x>")
1505-
;; Act linewise in Visual state
1506-
(when (and (evil-visual-state-p) (eq type 'inclusive))
1507-
(let ((range (evil-expand
1508-
beg end
1509-
(if (and evil-respect-visual-line-mode visual-line-mode)
1510-
'screen-line 'line))))
1511-
(setq beg (car range)
1512-
end (cadr range)
1513-
type (evil-type range))))
1514-
(if (eq type 'block)
1515-
;; Equivalent to $d, i.e., we use the block-to-eol selection and
1516-
;; call `evil-delete'. In this case we fake the call to
1517-
;; `evil-end-of-line' by setting `temporary-goal-column' and
1518-
;; `last-command' appropriately as `evil-end-of-line' would do.
1519-
(let ((temporary-goal-column most-positive-fixnum)
1520-
(last-command 'next-line))
1521-
(evil-delete beg end 'block register yank-handler))
1522-
(evil-delete beg end type register yank-handler)))
1519+
(cl-destructuring-bind
1520+
(beg end type) (evil-expand-line-for-line-based-operators beg end type)
1521+
(if (eq type 'block)
1522+
;; Equivalent to $d, i.e., we use the block-to-eol selection and
1523+
;; call `evil-delete'. In this case we fake the call to
1524+
;; `evil-end-of-line' by setting `temporary-goal-column' and
1525+
;; `last-command' appropriately as `evil-end-of-line' would do.
1526+
(let ((temporary-goal-column most-positive-fixnum)
1527+
(last-command 'next-line))
1528+
(evil-delete beg end 'block register yank-handler))
1529+
(evil-delete beg end type register yank-handler))))
15231530

15241531
(evil-define-operator evil-delete-whole-line
15251532
(beg end type register yank-handler)
@@ -1672,7 +1679,8 @@ of the block."
16721679
:motion evil-end-of-line-or-visual-line
16731680
(interactive "<R><x><y>")
16741681
(if (and (evil-visual-state-p) (eq type 'inclusive))
1675-
(cl-destructuring-bind (beg end &rest) (evil-line-expand beg end)
1682+
(cl-destructuring-bind
1683+
(beg end _type) (evil-expand-line-for-line-based-operators beg end type)
16761684
(evil-change-whole-line beg end register yank-handler))
16771685
(evil-change beg end type register yank-handler #'evil-delete-line)))
16781686

evil-tests.el

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2013,6 +2013,20 @@ New Tex[t]
20132013
("my" "G" ":'y,.y")
20142014
"1\n2\n3\n4\n5\n6\n7\n8\n9\n[1]0")))
20152015

2016+
(ert-deftest evil-test-yank-line ()
2017+
"Test `evil-yank-line'"
2018+
:tags '(evil operator)
2019+
(ert-info ("Yank line with eof being part of visual selection")
2020+
(evil-test-buffer
2021+
";; This is line one
2022+
;; This is lin[e] two
2023+
;; This is line three"
2024+
("v$Yjp")
2025+
";; This is line one
2026+
;; This is line two
2027+
;; This is line three
2028+
[;]; This is line two")))
2029+
20162030
(ert-deftest evil-test-delete ()
20172031
"Test `evil-delete'"
20182032
:tags '(evil operator delete)
@@ -2144,7 +2158,15 @@ ine3 line3 line3 l\n"))
21442158
(evil-test-buffer
21452159
"a[a]a\nbbb\nc\n"
21462160
("2D")
2147-
"a\nc\n")))
2161+
"a\nc\n"))
2162+
(ert-info ("Delete line with eof being part of visual selection")
2163+
(evil-test-buffer
2164+
";; This is line one
2165+
;; This is lin[e] two
2166+
;; This is line three"
2167+
("v$D")
2168+
";; This is line one
2169+
;; This is line three")))
21482170

21492171
(ert-deftest evil-test-delete-folded ()
21502172
"Test `evil-delete' on folded lines."
@@ -2342,6 +2364,19 @@ ABCthen enter the text in that file's own buffer.")))
23422364
[]
23432365
five")))
23442366

2367+
(ert-deftest evil-test-change-line ()
2368+
"Test `evil-change-line'"
2369+
:tags '(evil operator)
2370+
(ert-info ("Change line with eof being part of visual selection")
2371+
(evil-test-buffer
2372+
"This is line one
2373+
This is lin[e] two
2374+
This is line three"
2375+
("v$C")
2376+
"This is line one
2377+
[]
2378+
This is line three")))
2379+
23452380
(ert-deftest evil-test-change-word ()
23462381
"Test changing words"
23472382
:tags '(evil operator)

0 commit comments

Comments
 (0)