update mc
[emacs.git] / .emacs.d / elisp / multiple-cursors / mc-mark-more.el
index ac669fc..c957ce8 100644 (file)
@@ -173,9 +173,9 @@ With zero ARG, skip the last one and mark next."
   (dotimes (i num-lines)
     (mc/create-fake-cursor-at-point)
     (ecase direction
-      (forwards (loop do (next-line 1 nil)
+      (forwards (loop do (next-logical-line 1 nil)
                       while (mc/all-fake-cursors (point) (1+ (point)))))
-      (backwards (loop do (previous-line 1 nil)
+      (backwards (loop do (previous-logical-line 1 nil)
                        while (mc/all-fake-cursors (point) (1+ (point))))))))
 
 ;;;###autoload
@@ -191,17 +191,29 @@ With zero ARG, skip the last one and mark next."
   (mc/maybe-multiple-cursors-mode))
 
 ;;;###autoload
-(defun mc/unmark-next-like-this (arg)
+(defun mc/unmark-next-like-this ()
   "Deselect next part of the buffer matching the currently active region."
   (interactive)
   (mc/mark-next-like-this -1))
 
 ;;;###autoload
-(defun mc/unmark-previous-like-this (arg)
+(defun mc/unmark-previous-like-this ()
   "Deselect prev part of the buffer matching the currently active region."
   (interactive)
   (mc/mark-previous-like-this -1))
 
+;;;###autoload
+(defun mc/skip-to-next-like-this ()
+  "Skip the current one and select the next part of the buffer matching the currently active region."
+  (interactive)
+  (mc/mark-next-like-this 0))
+
+;;;###autoload
+(defun mc/skip-to-previous-like-this ()
+  "Skip the current one and select the prev part of the buffer matching the currently active region."
+  (interactive)
+  (mc/mark-previous-like-this 0))
+
 ;;;###autoload
 (defun mc/mark-all-like-this ()
   "Find and mark all the parts of the buffer matching the currently active region"
@@ -256,65 +268,125 @@ With zero ARG, skip the last one and mark next."
   (interactive "r")
   (let ((search (read-from-minibuffer "Mark all in region: "))
         (case-fold-search nil))
-    (mc/remove-fake-cursors)
-    (goto-char beg)
-    (while (search-forward search end t)
-      (push-mark (match-beginning 0))
-      (mc/create-fake-cursor-at-point))
-    (let ((first (mc/furthest-cursor-before-point)))
-      (if (not first)
-          (error "Search failed for %S" search)
-        (mc/pop-state-from-overlay first))))
-  (if (> (mc/num-cursors) 1)
-      (multiple-cursors-mode 1)
-    (multiple-cursors-mode 0)))
+    (if (string= search "")
+        (message "Mark aborted")
+      (progn
+        (mc/remove-fake-cursors)
+        (goto-char beg)
+        (while (search-forward search end t)
+          (push-mark (match-beginning 0))
+          (mc/create-fake-cursor-at-point))
+        (let ((first (mc/furthest-cursor-before-point)))
+          (if (not first)
+              (error "Search failed for %S" search)
+            (mc/pop-state-from-overlay first)))
+        (if (> (mc/num-cursors) 1)
+            (multiple-cursors-mode 1)
+          (multiple-cursors-mode 0))))))
+
+(when (not (fboundp 'set-temporary-overlay-map))
+  ;; Backport this function from newer emacs versions
+  (defun set-temporary-overlay-map (map &optional keep-pred)
+    "Set a new keymap that will only exist for a short period of time.
+The new keymap to use must be given in the MAP variable. When to
+remove the keymap depends on user input and KEEP-PRED:
+
+- if KEEP-PRED is nil (the default), the keymap disappears as
+  soon as any key is pressed, whether or not the key is in MAP;
+
+- if KEEP-PRED is t, the keymap disappears as soon as a key *not*
+  in MAP is pressed;
+
+- otherwise, KEEP-PRED must be a 0-arguments predicate that will
+  decide if the keymap should be removed (if predicate returns
+  nil) or kept (otherwise). The predicate will be called after
+  each key sequence."
+
+    (let* ((clearfunsym (make-symbol "clear-temporary-overlay-map"))
+           (overlaysym (make-symbol "t"))
+           (alist (list (cons overlaysym map)))
+           (clearfun
+            `(lambda ()
+               (unless ,(cond ((null keep-pred) nil)
+                              ((eq t keep-pred)
+                               `(eq this-command
+                                    (lookup-key ',map
+                                                (this-command-keys-vector))))
+                              (t `(funcall ',keep-pred)))
+                 (remove-hook 'pre-command-hook ',clearfunsym)
+                 (setq emulation-mode-map-alists
+                       (delq ',alist emulation-mode-map-alists))))))
+      (set overlaysym overlaysym)
+      (fset clearfunsym clearfun)
+      (add-hook 'pre-command-hook clearfunsym)
+
+      (push alist emulation-mode-map-alists))))
 
 ;;;###autoload
 (defun mc/mark-more-like-this-extended ()
   "Like mark-more-like-this, but then lets you adjust with arrows key.
-The actual adjustment made depends on the final component of the
-key-binding used to invoke the command, with all modifiers removed:
-
-   <up>    Mark previous like this
-   <down>  Mark next like this
-   <left>  If last was previous, skip it
-           If last was next, remove it
-   <right> If last was next, skip it
-           If last was previous, remove it
-
-Then, continue to read input events and further add or move marks
-as long as the input event read (with all modifiers removed)
-is one of the above."
+The adjustments work like this:
+
+   <up>    Mark previous like this and set direction to 'up
+   <down>  Mark next like this and set direction to 'down
+
+If direction is 'up:
+
+   <left>  Skip past the cursor furthest up
+   <right> Remove the cursor furthest up
+
+If direction is 'down:
+
+   <left>  Remove the cursor furthest down
+   <right> Skip past the cursor furthest down
+
+The bindings for these commands can be changed. See `mc/mark-more-like-this-extended-keymap'."
+  (interactive)
+  (mc/mmlte--down)
+  (set-temporary-overlay-map mc/mark-more-like-this-extended-keymap t))
+
+(defvar mc/mark-more-like-this-extended-direction nil
+  "When using mc/mark-more-like-this-extended are we working on the next or previous cursors?")
+
+(make-variable-buffer-local 'mc/mark-more-like-this-extended)
+
+(defun mc/mmlte--message ()
+  (if (eq mc/mark-more-like-this-extended-direction 'up)
+      (message "<up> to mark previous, <left> to skip, <right> to remove, <down> to mark next")
+    (message "<down> to mark next, <right> to skip, <left> to remove, <up> to mark previous")))
+
+(defun mc/mmlte--up ()
+  (interactive)
+  (mc/mark-previous-like-this 1)
+  (setq mc/mark-more-like-this-extended-direction 'up)
+  (mc/mmlte--message))
+
+(defun mc/mmlte--down ()
+  (interactive)
+  (mc/mark-next-like-this 1)
+  (setq mc/mark-more-like-this-extended-direction 'down)
+  (mc/mmlte--message))
+
+(defun mc/mmlte--left ()
+  (interactive)
+  (if (eq mc/mark-more-like-this-extended-direction 'down)
+      (mc/unmark-next-like-this)
+    (mc/skip-to-previous-like-this))
+  (mc/mmlte--message))
+
+(defun mc/mmlte--right ()
   (interactive)
-  (let ((first t)
-        (ev last-command-event)
-        (cmd 'mc/mark-next-like-this)
-        (arg 1)
-        last echo-keystrokes)
-    (while cmd
-      (let ((base (event-basic-type ev)))
-        (cond ((eq base 'left)
-               (if (eq last 'mc/mark-previous-like-this)
-                   (setq cmd last arg 0)
-                 (setq cmd 'mc/mark-next-like-this arg -1)))
-              ((eq base 'up)
-               (setq cmd 'mc/mark-previous-like-this arg 1))
-              ((eq base 'right)
-               (if (eq last 'mc/mark-next-like-this)
-                   (setq cmd last arg 0)
-                 (setq cmd 'mc/mark-previous-like-this arg -1)))
-              ((eq base 'down)
-               (setq cmd 'mc/mark-next-like-this arg 1))
-              (first
-               (setq cmd 'mc/mark-next-like-this arg 1))
-              (t
-               (setq cmd nil))))
-      (when cmd
-        (ignore-errors
-          (funcall cmd arg))
-        (setq first nil last cmd)
-        (setq ev (read-event "Use arrow keys for more marks: "))))
-    (push ev unread-command-events)))
+  (if (eq mc/mark-more-like-this-extended-direction 'up)
+      (mc/unmark-previous-like-this)
+    (mc/skip-to-next-like-this))
+  (mc/mmlte--message))
+
+(defvar mc/mark-more-like-this-extended-keymap (make-sparse-keymap))
+
+(define-key mc/mark-more-like-this-extended-keymap (kbd "<up>") 'mc/mmlte--up)
+(define-key mc/mark-more-like-this-extended-keymap (kbd "<down>") 'mc/mmlte--down)
+(define-key mc/mark-more-like-this-extended-keymap (kbd "<left>") 'mc/mmlte--left)
+(define-key mc/mark-more-like-this-extended-keymap (kbd "<right>") 'mc/mmlte--right)
 
 (defvar mc--restrict-mark-all-to-symbols nil)
 
@@ -347,6 +419,28 @@ With prefix, it behaves the same as original `mc/mark-all-like-this'"
         (when (<= (mc/num-cursors) before)
           (mc/mark-all-like-this))))))
 
+;;;###autoload
+(defun mc/mark-all-dwim (arg)
+  "Tries even harder to guess what you want to mark all of.
+
+If the region is active and spans multiple lines, it will behave
+as if `mc/mark-all-in-region'. With the prefix ARG, it will call
+`mc/edit-lines' instead.
+
+If the region is inactive or on a single line, it will behave like 
+`mc/mark-all-like-this-dwim'."
+  (interactive "P")
+  (if (and (use-region-p)
+           (not (> (mc/num-cursors) 1))
+           (not (= (line-number-at-pos (region-beginning))
+                   (line-number-at-pos (region-end)))))
+      (if arg
+          (call-interactively 'mc/edit-lines)
+       (call-interactively 'mc/mark-all-in-region))
+    (progn
+      (setq this-command 'mc/mark-all-like-this-dwim)
+      (mc/mark-all-like-this-dwim arg))))
+
 (defun mc--in-defun ()
   (bounds-of-thing-at-point 'defun))