aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustin Burkett <justin@burkett.cc>2019-08-08 21:50:50 -0400
committerEivind Fonn <evfonn@gmail.com>2019-11-19 11:34:20 +0100
commit5365e4d79f7f9c9e04d8d4f9b02b087791c18db2 (patch)
treeea047fe8d9012bf3e60a00d431b9d9a1ee0bb6ae
parent92102f3b30d03d1d87b34ae2c01e4bc2013d5129 (diff)
Make more commands support visual-line-mode
when evil-respect-visual-line-mode is non-nil, including evil-change-line, evil-delete-line, and evil-yank-line. Most of the work is done through the motions evil-line-or-visual-line and evil-end-of-line-or-visual-line. These motions use visual lines when visual-line-mode and evil-respect-visual-line-mode are non-nil, and revert back to standard lines otherwise. Visual selection via visual lines in the sense of visual-line-mode is supported by adding a new screen-line type (named to avoid confusion with visual state).
-rw-r--r--evil-commands.el64
-rw-r--r--evil-integration.el32
-rw-r--r--evil-macros.el2
-rw-r--r--evil-states.el4
-rw-r--r--evil-types.el30
-rw-r--r--evil-vars.el17
6 files changed, 115 insertions, 34 deletions
diff --git a/evil-commands.el b/evil-commands.el
index 7d87d6b..6efa2cd 100644
--- a/evil-commands.el
+++ b/evil-commands.el
@@ -162,6 +162,18 @@ of the line or the buffer; just return nil."
(evil-line-move (1- (or count 1)))
((beginning-of-buffer end-of-buffer)))))
+(evil-define-motion evil-line-or-visual-line (count)
+ "Move COUNT - 1 lines down."
+ :type screen-line
+ (let ((line-move-visual (and evil-respect-visual-line-mode
+ visual-line-mode)))
+ ;; Catch bob and eob errors. These are caused when not moving
+ ;; point starting in the first or last line, respectively. In this
+ ;; case the current line should be selected.
+ (condition-case err
+ (evil-line-move (1- (or count 1)))
+ ((beginning-of-buffer end-of-buffer)))))
+
(evil-define-motion evil-beginning-of-line ()
"Move the cursor to the beginning of the current line."
:type exclusive
@@ -196,6 +208,18 @@ If COUNT is given, move COUNT - 1 screen lines downward first."
(end-of-visual-line count)
(end-of-line count)))
+(evil-define-motion evil-end-of-line-or-visual-line (count)
+ "Move the cursor to the last character of the current screen
+line if `visual-line-mode' is active and
+`evil-respect-visual-line-mode' is non-nil. If COUNT is given,
+move COUNT - 1 screen lines downward first."
+ :type inclusive
+ (if (and (fboundp 'end-of-visual-line)
+ evil-respect-visual-line-mode
+ visual-line-mode)
+ (end-of-visual-line count)
+ (evil-end-of-line count)))
+
(evil-define-motion evil-middle-of-visual-line ()
"Move the cursor to the middle of the current visual line."
:type exclusive
@@ -1344,12 +1368,16 @@ or line COUNT to the top of the window."
(evil-define-operator evil-yank-line (beg end type register)
"Saves whole lines into the kill-ring."
- :motion evil-line
+ :motion evil-line-or-visual-line
:move-point nil
(interactive "<R><x>")
(when (evil-visual-state-p)
- (unless (memq type '(line block))
- (let ((range (evil-expand beg end 'line)))
+ (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))))
(setq beg (evil-range-beginning range)
end (evil-range-end range)
type (evil-type range))))
@@ -1391,10 +1419,20 @@ Save in REGISTER or in the kill-ring with YANK-HANDLER."
(interactive "<R><x>")
;; act linewise in Visual state
(let* ((beg (or beg (point)))
- (end (or end beg)))
+ (end (or end beg))
+ (visual-line-mode (and evil-respect-visual-line-mode
+ visual-line-mode))
+ (line-end (if visual-line-mode
+ (save-excursion
+ (end-of-visual-line)
+ (point))
+ (line-end-position))))
(when (evil-visual-state-p)
- (unless (memq type '(line block))
- (let ((range (evil-expand beg end 'line)))
+ (unless (memq type '(line screen-line block))
+ (let ((range (evil-expand beg end
+ (if visual-line-mode
+ 'screen-line
+ 'line))))
(setq beg (evil-range-beginning range)
end (evil-range-end range)
type (evil-type range))))
@@ -1408,15 +1446,15 @@ Save in REGISTER or in the kill-ring with YANK-HANDLER."
(let ((temporary-goal-column most-positive-fixnum)
(last-command 'next-line))
(evil-delete beg end 'block register yank-handler)))
- ((eq type 'line)
+ ((memq type '(line screen-line))
(evil-delete beg end type register yank-handler))
(t
- (evil-delete beg (line-end-position) type register yank-handler)))))
+ (evil-delete beg line-end type register yank-handler)))))
(evil-define-operator evil-delete-whole-line
(beg end type register yank-handler)
"Delete whole line."
- :motion evil-line
+ :motion evil-line-or-visual-line
(interactive "<R><x>")
(evil-delete beg end type register yank-handler))
@@ -1515,20 +1553,20 @@ of the block."
(evil-define-operator evil-change-line (beg end type register yank-handler)
"Change to end of line."
- :motion evil-end-of-line
+ :motion evil-end-of-line-or-visual-line
(interactive "<R><x><y>")
(evil-change beg end type register yank-handler #'evil-delete-line))
(evil-define-operator evil-change-whole-line
(beg end type register yank-handler)
"Change whole line."
- :motion evil-line
+ :motion evil-line-or-visual-line
(interactive "<R><x>")
(evil-change beg end type register yank-handler #'evil-delete-whole-line))
(evil-define-command evil-copy (beg end address)
"Copy lines in BEG END below line given by ADDRESS."
- :motion evil-line
+ :motion evil-line-or-visual-line
(interactive "<r><addr>")
(goto-char (point-min))
(forward-line address)
@@ -1543,7 +1581,7 @@ of the block."
(evil-define-command evil-move (beg end address)
"Move lines in BEG END below line given by ADDRESS."
- :motion evil-line
+ :motion evil-line-or-visual-line
(interactive "<r><addr>")
(goto-char (point-min))
(forward-line address)
diff --git a/evil-integration.el b/evil-integration.el
index bab8bde..50eff30 100644
--- a/evil-integration.el
+++ b/evil-integration.el
@@ -490,13 +490,31 @@ Based on `evil-enclose-ace-jump-for-motion'."
;; visual-line-mode integration
(when evil-respect-visual-line-mode
- (let ((swaps '((evil-next-line . evil-next-visual-line)
- (evil-previous-line . evil-previous-visual-line)
- (evil-beginning-of-line . evil-beginning-of-visual-line)
- (evil-end-of-line . evil-end-of-visual-line))))
- (dolist (swap swaps)
- (define-key visual-line-mode-map (vector 'remap (car swap)) (cdr swap))
- (define-key visual-line-mode-map (vector 'remap (cdr swap)) (car swap)))))
+ (evil-define-command evil-digit-argument-or-beginning-of-visual-line ()
+ :digit-argument-redirection evil-beginning-of-visual-line
+ :keep-visual t
+ :repeat nil
+ (interactive)
+ (cond
+ (current-prefix-arg
+ (setq this-command #'digit-argument)
+ (call-interactively #'digit-argument))
+ (t
+ (let ((target (or (command-remapping #'evil-beginning-of-visual-line)
+ #'evil-beginning-of-visual-line)))
+ (setq this-command 'evil-beginning-of-visual-line)
+ (call-interactively 'evil-beginning-of-visual-line)))))
+
+ (evil-define-minor-mode-key 'motion 'visual-line-mode
+ "j" 'evil-next-visual-line
+ "gj" 'evil-next-line
+ "k" 'evil-previous-visual-line
+ "gk" 'evil-previous-line
+ "0" 'evil-digit-argument-or-evil-beginning-of-visual-line
+ "g0" 'evil-beginning-of-line
+ "$" 'evil-end-of-visual-line
+ "g$" 'evil-end-of-line
+ "V" 'evil-visual-screen-line))
;;; abbrev.el
(when evil-want-abbrev-expand-on-insert-exit
diff --git a/evil-macros.el b/evil-macros.el
index b820545..3af95d4 100644
--- a/evil-macros.el
+++ b/evil-macros.el
@@ -557,7 +557,7 @@ RETURN-TYPE is non-nil."
(setq keys (listify-key-sequence keys))
(dotimes (var (length keys))
(define-key evil-operator-shortcut-map
- (vconcat (nthcdr var keys)) 'evil-line)))
+ (vconcat (nthcdr var keys)) 'evil-line-or-visual-line)))
;; read motion from keyboard
(setq command (evil-read-motion motion)
motion (nth 0 command)
diff --git a/evil-states.el b/evil-states.el
index 8ffc1d6..7d029b3 100644
--- a/evil-states.el
+++ b/evil-states.el
@@ -258,6 +258,10 @@ the selection is enabled.
"Linewise selection."
:message "-- VISUAL LINE --")
+(evil-define-visual-selection screen-line
+ "Linewise selection in `visual-line-mode'."
+ :message "-- SCREEN LINE --")
+
(evil-define-visual-selection block
"Blockwise selection."
:message "-- VISUAL BLOCK --"
diff --git a/evil-types.el b/evil-types.el
index 2c6b4f2..1e257ef 100644
--- a/evil-types.el
+++ b/evil-types.el
@@ -141,6 +141,36 @@ line and `evil-want-visual-char-semi-exclusive', then:
(format "%s line%s" height
(if (= height 1) "" "s")))))
+(evil-define-type screen-line
+ "Include whole lines, being aware of `visual-line-mode'
+when `evil-respect-visual-line-mode' is non-nil."
+ :one-to-one nil
+ :expand (lambda (beg end)
+ (if (or (not evil-respect-visual-line-mode)
+ (not visual-line-mode))
+ (evil-line-expand beg end)
+ (evil-range
+ (progn
+ (goto-char beg)
+ (save-excursion
+ (beginning-of-visual-line)))
+ (progn
+ (goto-char end)
+ (save-excursion
+ ;; `beginning-of-visual-line' reverts to the beginning of the
+ ;; last visual line if the end of the last line is the end of
+ ;; the buffer. This would prevent selecting the last screen
+ ;; line.
+ (if (= (line-beginning-position 2) (point-max))
+ (point-max)
+ (beginning-of-visual-line 2)))))))
+ :contract (lambda (beg end)
+ (evil-range beg (max beg (1- end))))
+ :string (lambda (beg end)
+ (let ((height (count-screen-lines beg end)))
+ (format "%s screen line%s" height
+ (if (= height 1) "" "s")))))
+
(evil-define-type block
"Like `inclusive', but for rectangles:
the last column is included."
diff --git a/evil-vars.el b/evil-vars.el
index d95450c..d10a4a8 100644
--- a/evil-vars.el
+++ b/evil-vars.el
@@ -218,18 +218,7 @@ a line."
(defcustom evil-respect-visual-line-mode nil
"Whether movement commands respect `visual-line-mode'.
-This variable must be set before Evil is loaded. When
-`visual-line-mode' is active, the following commands are swapped
-
-`evil-next-line' <-> `evil-next-visual-line'
-`evil-previous-line' <-> `evil-previous-visual-line'
-`evil-beginning-of-line' <-> `evil-beginning-of-visual-line'
-`evil-end-of-line' <-> `evil-end-of-visual-line'
-
-The commands `evil-insert-line', `evil-append-line',
-`evil-find-char', `evil-find-char-backward', `evil-find-char-to'
-and `evil-find-char-to-backward' are also made aware of visual
-lines."
+This variable must be set before Evil is loaded."
:type 'boolean
:group 'evil)
@@ -506,7 +495,9 @@ The default behavior is to yank the whole line."
:set #'(lambda (sym value)
(evil-add-command-properties
'evil-yank-line
- :motion (if value 'evil-end-of-line 'evil-line))))
+ :motion (if value
+ 'evil-end-of-line-or-visual-line
+ 'evil-line-or-visual-line))))
(defcustom evil-disable-insert-state-bindings nil
"Whether insert state bindings should be used. Excludes