From 53e205d2e1fb968146037442c47e0ac8381ba4e2 Mon Sep 17 00:00:00 2001 From: Frank Fischer Date: Thu, 7 Jan 2016 08:28:47 +0100 Subject: Handle forced linewise non-visual text-objects (re #607) --- evil-common.el | 4 +++- evil-macros.el | 64 +++++++++++++++++++++++++++++++++++++--------------------- evil-tests.el | 12 ++++++++++- evil-vars.el | 5 +++++ 4 files changed, 60 insertions(+), 25 deletions(-) diff --git a/evil-common.el b/evil-common.el index d48d2f5..94182bf 100644 --- a/evil-common.el +++ b/evil-common.el @@ -635,6 +635,7 @@ Return a list (MOTION COUNT [TYPE])." (evil-visual-line . line) (evil-visual-block . block))) command prefix) + (setq evil-this-type-modified nil) (unless motion (while (progn (setq command (evil-keypress-parser) @@ -660,7 +661,8 @@ Return a list (MOTION COUNT [TYPE])." (setq type 'inclusive) (setq type 'exclusive))) (t - (setq type modifier)))) + (setq type modifier))) + (setq evil-this-type-modified type)) (list motion count type))) (defun evil-mouse-events-p (keys) diff --git a/evil-macros.el b/evil-macros.el index a03aa28..c1ec5b2 100644 --- a/evil-macros.el +++ b/evil-macros.el @@ -315,6 +315,36 @@ of the object; otherwise it is placed at the end of the object." (t count)))) +(defun evil-text-object-make-linewise (beg end) + "Turn the text object selection between BEG and END to linewise. +The selection is adjusted in a sensible way so that the selected +lines match the user intent. In particular, whitespace-only parts +at the first and last lines are omitted. This function returns +the new pair (BEG . END) of buffer positions." + ;; Bug #607 + ;; If new type is linewise and the selection of the + ;; first line consists of whitespace only, the + ;; beginning is moved to the start of the next line. If + ;; the selections of the last line consists of + ;; whitespace only, the end is moved to the end of the + ;; previous line. + (let ((newbeg beg) (newend end)) + (save-excursion + ;; skip whitespace at the beginning + (goto-char beg) + (skip-chars-forward " \t") + (when (and (not (bolp)) (eolp)) + (setq newbeg (1+ (point)))) + ;; skip whitepsace at the end + (goto-char end) + (skip-chars-backward " \t") + (when (and (not (eolp)) (bolp)) + (setq newend (1- (point)))) + ;; only modify range if result is not empty + (if (<= newbeg newend) + (cons newbeg newend) + (cons beg end))))) + (defmacro evil-define-text-object (object args &rest body) "Define a text object command OBJECT. BODY should return a range (BEG END) to the right of point @@ -379,30 +409,10 @@ if COUNT is positive, and to the left of it if negative. (if evil-text-object-change-visual-type range (evil-visual-range)))) - ;; Bug #607 - ;; If new type is linewise and the selection of the - ;; first line consists of whitespace only, the - ;; beginning is moved to the start of the next line. If - ;; the selections of the last line consists of - ;; whitespace only, the end is moved to the end of the - ;; previous line. (when (eq type 'line) - (let ((beg mark) (end point)) - (save-excursion - ;; skip whitespace at the beginning - (goto-char beg) - (skip-chars-forward " \t") - (when (and (not (bolp)) (eolp)) - (setq beg (1+ (point)))) - ;; skip whitepsace at the end - (goto-char end) - (skip-chars-backward " \t") - (when (and (not (eolp)) (bolp)) - (setq end (1- (point)))) - ;; only modify range if result is not empty - (when (<= beg end) - (setq mark beg) - (setq point end))))) + (let ((newsel (evil-text-object-make-linewise mark point))) + (setq mark (car newsel) + point (cdr newsel)))) (when (< dir 0) (evil-swap mark point)) ;; select the union @@ -421,6 +431,13 @@ if COUNT is positive, and to the left of it if negative. ;; ensure the range is properly expanded (evil-contract-range range) (evil-expand-range range) + ;; possibly convert to linewise + (when (eq evil-this-type-modified 'line) + (let ((newsel (evil-text-object-make-linewise + (evil-range-beginning range) + (evil-range-end range)))) + (evil-set-range-beginning range (car newsel)) + (evil-set-range-end range (cdr newsel)) )) (evil-set-range-properties range nil) range)))))))) @@ -515,6 +532,7 @@ RETURN-TYPE is non-nil." (type evil-operator-range-type) (range (evil-range (point) (point))) command count modifier) + (setq evil-this-type-modified nil) (evil-save-echo-area (cond ;; Ex mode diff --git a/evil-tests.el b/evil-tests.el index de80008..0cfa4db 100644 --- a/evil-tests.el +++ b/evil-tests.el @@ -6298,7 +6298,17 @@ Below some empty line.")) this.var2 = something_else(); return something_nasty();[\n]> } " - (should (eq (evil-visual-type) 'line)))))) + (should (eq (evil-visual-type) 'line))))) + (ert-info ("Forced motion type should change text object type") + (evil-test-buffer + "for (int i=0; i<10; i++) { + if ([c]ond) { + do_something(); + } +}" + ("dVi}") + "for (int i=0; i<10; i++) { +\[}]"))) (ert-deftest evil-test-tag-objects () "Test `evil-inner-tag', etc." diff --git a/evil-vars.el b/evil-vars.el index 53ec3b0..9e8c49c 100644 --- a/evil-vars.el +++ b/evil-vars.el @@ -1230,6 +1230,11 @@ describing it, etc.") (evil-define-local-var evil-this-type nil "Current motion type.") +(evil-define-local-var evil-this-type-modified nil + "Non-nil iff current motion type has been modified by the user. +If the type has been modified, this variable contains the new +type.") + (evil-define-local-var evil-this-register nil "Current register.") -- cgit v1.0