From 39c4700b3bac6bdd8dbd9ff20ceb6bca2bcf5575 Mon Sep 17 00:00:00 2001 From: Henrik Lissner Date: Fri, 19 Feb 2016 12:33:16 -0500 Subject: [PATCH] Add multiple cursors implementation with iedit --- core/defuns/defuns-iedit.el | 72 +++++++++++++++++++++++++++---------- private/my-bindings.el | 4 +-- 2 files changed, 55 insertions(+), 21 deletions(-) diff --git a/core/defuns/defuns-iedit.el b/core/defuns/defuns-iedit.el index 7be259815..8e84c0041 100644 --- a/core/defuns/defuns-iedit.el +++ b/core/defuns/defuns-iedit.el @@ -13,33 +13,67 @@ (evil-previous-line)) (call-interactively 'evil-ret))) +;; Many packages try to do the multiple-cursors thing, but when it comes to +;; multiple-cursors and evil-mode, things get complicated. `evil-mc' doesn't seem stable +;; enough (I haven't been able to get it to work with my setup), `multiple-cursors' +;; doesn't work well with evil's vimmish opinion of where the cursor is... +;; +;; So, this is my solution: using `iedit' and `evil-iedit-mode', I wrote +;; `narf/mark-and-next' and `narf/mark-and-prev', and it works like a charm! When I want +;; "match all" functionality, I use `evil-iedit-mode/iedit-mode' while in visual mode and +;; I get just that. + +(defvar narf-mark-first nil) +(defvar narf-mark-pt nil) +(defvar narf-mark-index '(1 . 1)) + +(defun narf|mark-end () + (setq narf-mark-first nil + narf-mark-pt nil + narf-mark-index (cons 1 1))) +(add-hook! (iedit-mode-end-hook iedit-aborting) 'narf|mark-end) + ;;;###autoload (defun narf/mark-and-prev () + "See `narf/mark-and-next'" (interactive) (narf/mark-and-next t)) ;;;###autoload (defun narf/mark-and-next (&optional backwards-p) + "Emulates Sublime Text's (and Atom's) multiple cursors functionality by marking the +current word/selection and marking the next one on consecutive executions of this +function." (interactive) - (let ((beg evil-visual-beginning) - (end evil-visual-end) - (last-pos (point))) - (unless (bound-and-true-p evil-iedit-state-local-minor-mode) - (save-excursion - (funcall (intern (format "evil-visualstar/begin-search-%s" (if backwards-p "backward" "forward"))) - beg end)) - (when backwards-p - (goto-char beg)) - (evil-visual-make-region beg end) - (call-interactively 'evil-iedit-state/iedit-mode) - (save-excursion - (narf:iedit-restrict-to-region beg end))) - (evil-ex-find-next nil (if backwards-p 'backward 'forward) t) - ;; (evil-ex-search-next) - (evil-ex-nohighlight) - (when (and (iedit-find-current-occurrence-overlay) - (if backwards-p t (not (= last-pos (point))))) - (iedit-toggle-selection)))) + (setq evil-ex-search-direction (if backwards-p 'backward 'forward)) + (save-excursion + (if narf-mark-first + (let ((i (if backwards-p (cdr narf-mark-index) (car narf-mark-index)))) + (goto-char narf-mark-pt) + (while (and (> i 0) + (evil-ex-find-next nil (if backwards-p 'backward 'forward) t)) + (decf i)) + (if (> i 0) + (message "End of the buffer!") + (incf (if backwards-p + (cdr narf-mark-index) + (car narf-mark-index)))) + (unless (iedit-find-current-occurrence-overlay) + (iedit-toggle-selection))) + (let* ((bounds (if (evil-visual-state-p) + (cons evil-visual-beginning evil-visual-end) + (bounds-of-thing-at-point 'word))) + (beg (car bounds)) + (end (cdr bounds)) + (occurrence (buffer-substring-no-properties (car bounds) (cdr bounds)))) + (setq narf-mark-first (if backwards-p beg end) + narf-mark-pt (if backwards-p beg end)) + (evil-normal-state) + (setq iedit-initial-string-local occurrence) + (iedit-start (iedit-regexp-quote occurrence) beg end) + (evil-iedit-state) + (setq evil-ex-search-pattern (evil-ex-make-search-pattern (regexp-quote occurrence))) + (evil-ex-find-next nil nil t))))) (provide 'defuns-iedit) ;;; defuns-iedit.el ends here diff --git a/private/my-bindings.el b/private/my-bindings.el index 535695acf..6ae6253be 100644 --- a/private/my-bindings.el +++ b/private/my-bindings.el @@ -258,8 +258,8 @@ ;; iedit and my own version of multiple-cursors :v "R" 'evil-iedit-state/iedit-mode ; edit all instances of marked region - :v "M-d" 'narf/mark-and-next - :v "M-D" 'narf/mark-and-prev + :nv "M-d" 'narf/mark-and-next + :nv "M-D" 'narf/mark-and-prev ;; aliases for % :m "%" 'evilmi-jump-items