[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/multiple-cursors c3b2d84 164/434: Merge pull request #23 f
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/multiple-cursors c3b2d84 164/434: Merge pull request #23 from segv/master |
Date: |
Sat, 7 Aug 2021 09:20:18 -0400 (EDT) |
branch: elpa/multiple-cursors
commit c3b2d8483b5ba6e8253a068504b722fd30cd810d
Merge: a0f771f 2818d9e
Author: Magnar Sveen <magnars@gmail.com>
Commit: Magnar Sveen <magnars@gmail.com>
Merge pull request #23 from segv/master
Improve mc/cycle and mc/mark-next/prev
---
features/mark-more.feature | 38 +++++++++++
features/multiple-cursors-core.feature | 14 ++++
mc-cycle-cursors.el | 63 ++++++++++++++----
mc-mark-more.el | 113 ++++++++++++++++++++-------------
multiple-cursors-core.el | 11 ++--
5 files changed, 177 insertions(+), 62 deletions(-)
diff --git a/features/mark-more.feature b/features/mark-more.feature
index 189b22c..8ca86f7 100644
--- a/features/mark-more.feature
+++ b/features/mark-more.feature
@@ -94,3 +94,41 @@ Feature: Marking multiple parts of the buffer
And I type "more"
Then I should have 2 cursors
And I should see "Here's more, more and text"
+
+ Scenario: Marking without an active region
+ When I insert:
+ """
+ aaa
+ bbb
+ ccc
+ """
+ And I go to the front of the word "bbb"
+ And I press "C->"
+ And I type "_"
+ Then I should have 2 cursors
+ And I should see:
+ """
+ aaa
+ _bbb
+ _ccc
+ """
+
+ Scenario: Increasing number of cursors without an active region
+ When I insert:
+ """
+ aaa
+ bbb
+ ccc
+ """
+ And I go to the front of the word "bbb"
+ And I press "C->"
+ And I press "C-<"
+ And i press "C-f"
+ And I type "_"
+ Then I should have 3 cursors
+ And I should see:
+ """
+ a_aa
+ b_bb
+ c_cc
+ """
diff --git a/features/multiple-cursors-core.feature
b/features/multiple-cursors-core.feature
index 46d14bf..8d8fb65 100644
--- a/features/multiple-cursors-core.feature
+++ b/features/multiple-cursors-core.feature
@@ -158,3 +158,17 @@ Feature: Multiple cursors core
contains
twice
"""
+
+ Scenario: Looping forwards around cursors
+ Given I have cursors at "_" in "1_34567_9"
+ And I press "C-v"
+ And I press "C-v"
+ And I press "C-v"
+ Then the cursor should be at point "8"
+
+ Scenario: Looping backwards around cursors
+ Given I have cursors at "_" in "1_34567_9"
+ And I press "M-v"
+ And I press "M-v"
+ Then the cursor should be at point "2"
+
diff --git a/mc-cycle-cursors.el b/mc-cycle-cursors.el
index f70a96a..46d7426 100644
--- a/mc-cycle-cursors.el
+++ b/mc-cycle-cursors.el
@@ -30,7 +30,7 @@
(eval-when-compile (require 'cl))
-(defun mc/next-cursor-after-point ()
+(defun mc/next-fake-cursor-after-point ()
(let ((pos (point))
(next-pos (point-max))
next)
@@ -42,7 +42,7 @@
(setq next cursor))))
next))
-(defun mc/prev-cursor-before-point ()
+(defun mc/prev-fake-cursor-before-point ()
(let ((pos (point))
(prev-pos (point-min))
prev)
@@ -54,23 +54,58 @@
(setq prev cursor))))
prev))
+(defcustom mc/cycle-looping-behaviour 'continue
+ "What to do if asked to cycle beyond the last cursor or before the first
cursor."
+ :type '(radio (const :tag "Loop around to beginning/end of document."
continue)
+ (const :tag "Warn and then loop around." warn)
+ (const :tag "Signal an error." error)
+ (const :tag "Don't loop." stop)))
+
+(defun mc/handle-loop-condition (error-message)
+ (ecase mc/cycle-looping-behaviour
+ (error (error error-message))
+ (warn (message error-message))
+ (continue 'continue)
+ (stop 'stop)))
+
+(defun mc/first-fake-cursor-after (point)
+ "Very similar to mc/furthest-cursor-before-point, but ignores (mark) and
(point)."
+ (let* ((cursors (mc/all-fake-cursors))
+ (cursors-after-point (remove-if (lambda (cursor)
+ (< (mc/cursor-beg cursor) point))
+ cursors))
+ (cursors-in-order (sort* cursors-after-point '< :key 'mc/cursor-beg)))
+ (first cursors-in-order)))
+
+(defun mc/last-fake-cursor-before (point)
+ "Very similar to mc/furthest-cursor-before-point, but ignores (mark) and
(point)."
+ (let* ((cursors (mc/all-fake-cursors))
+ (cursors-before-point (remove-if (lambda (cursor)
+ (> (mc/cursor-end cursor) point))
+ cursors))
+ (cursors-in-order (sort* cursors-before-point '> :key
'mc/cursor-end)))
+ (first cursors-in-order)))
+
+(defun* mc/cycle (next-cursor fallback-cursor loop-message)
+ (when (null next-cursor)
+ (when (eql 'stop (mc/handle-loop-condition loop-message))
+ (return-from mc/cycle nil))
+ (setf next-cursor fallback-cursor))
+ (mc/create-fake-cursor-at-point)
+ (mc/pop-state-from-overlay next-cursor)
+ (recenter))
+
(defun mc/cycle-forward ()
(interactive)
- (let ((next-cursor (mc/next-cursor-after-point)))
- (unless next-cursor
- (error "We're already at the last cursor"))
- (mc/create-fake-cursor-at-point)
- (mc/pop-state-from-overlay next-cursor)
- (recenter)))
+ (mc/cycle (mc/next-fake-cursor-after-point)
+ (mc/first-fake-cursor-after (point-min))
+ "We're already at the last cursor."))
(defun mc/cycle-backward ()
(interactive)
- (let ((prev-cursor (mc/prev-cursor-before-point)))
- (unless prev-cursor
- (error "We're already at the first cursor"))
- (mc/create-fake-cursor-at-point)
- (mc/pop-state-from-overlay prev-cursor)
- (recenter)))
+ (mc/cycle (mc/prev-fake-cursor-before-point)
+ (mc/last-fake-cursor-before (point-max))
+ "We're already at the last cursor"))
(define-key mc/keymap (kbd "C-v") 'mc/cycle-forward)
(define-key mc/keymap (kbd "M-v") 'mc/cycle-backward)
diff --git a/mc-mark-more.el b/mc-mark-more.el
index 883fb1e..7d722b0 100644
--- a/mc-mark-more.el
+++ b/mc-mark-more.el
@@ -79,34 +79,54 @@
(mc/cursor-end cursor))))
strings))
+(defun mc/maybe-multiple-cursors-mode ()
+ "Enable multiple-cursors-mode if there is more than one currently active
cursor."
+ (if (> (mc/num-cursors) 1)
+ (multiple-cursors-mode 1)
+ (multiple-cursors-mode 0)))
+
+(defun mc/mark-more-like-this (skip-last direction)
+ (let ((case-fold-search nil)
+ (re (regexp-opt (mc/region-strings)))
+ (point-out-of-order (ecase direction
+ (forwards (< (point) (mark)))
+ (backwards (not (< (point) (mark))))))
+ (furthest-cursor (ecase direction
+ (forwards (mc/furthest-cursor-after-point))
+ (backwards (mc/furthest-cursor-before-point))))
+ (start-char (ecase direction
+ (forwards (mc/furthest-region-end))
+ (backwards (mc/first-region-start))))
+ (search-function (ecase direction
+ (forwards 'search-forward-regexp)
+ (backwards 'search-backward-regexp)))
+ (match-point-getter (ecase direction
+ (forwards 'match-beginning)
+ (backwards 'match-end))))
+ (mc/save-excursion
+ (goto-char start-char)
+ (when skip-last
+ (mc/remove-fake-cursor furthest-cursor))
+ (if (funcall search-function re nil t)
+ (progn
+ (push-mark (funcall match-point-getter 0))
+ (when point-out-of-order
+ (exchange-point-and-mark))
+ (mc/create-fake-cursor-at-point))
+ (error "no more matches found.")))))
+
;;;###autoload
(defun mc/mark-next-like-this (arg)
"Find and mark the next part of the buffer matching the currently active
region
With negative ARG, delete the last one instead.
With zero ARG, skip the last one and mark next."
(interactive "p")
- (unless (region-active-p)
- (error "Mark a region to match first."))
- (when (< arg 0)
- (mc/remove-fake-cursor (mc/furthest-cursor-after-point)))
- (when (>= arg 0)
- (let ((case-fold-search nil)
- (point-first (< (point) (mark)))
- (re (regexp-opt (mc/region-strings)))
- (furthest-cursor (mc/furthest-cursor-after-point)))
- (mc/save-excursion
- (goto-char (mc/furthest-region-end))
- (when (= arg 0)
- (mc/remove-fake-cursor furthest-cursor))
- (if (search-forward-regexp re nil t)
- (progn
- (push-mark (match-beginning 0))
- (when point-first (exchange-point-and-mark))
- (mc/create-fake-cursor-at-point))
- (error "no more found forward")))))
- (if (> (mc/num-cursors) 1)
- (multiple-cursors-mode 1)
- (multiple-cursors-mode 0)))
+ (if (region-active-p)
+ (if (< arg 0)
+ (mc/remove-fake-cursor (mc/furthest-cursor-after-point))
+ (mc/mark-more-like-this (= arg 0) 'forwards))
+ (mc/mark-lines arg 'forwards))
+ (mc/maybe-multiple-cursors-mode))
;;;###autoload
(defun mc/mark-previous-like-this (arg)
@@ -114,28 +134,33 @@ With zero ARG, skip the last one and mark next."
With negative ARG, delete the last one instead.
With zero ARG, skip the last one and mark next."
(interactive "p")
- (unless (region-active-p)
- (error "Mark a region to match first."))
- (when (< arg 0)
- (mc/remove-fake-cursor (mc/furthest-cursor-before-point)))
- (when (>= arg 0)
- (let ((case-fold-search nil)
- (point-first (< (point) (mark)))
- (re (regexp-opt (mc/region-strings)))
- (furthest-cursor (mc/furthest-cursor-before-point)))
- (mc/save-excursion
- (goto-char (mc/first-region-start))
- (when (= arg 0)
- (mc/remove-fake-cursor furthest-cursor))
- (if (search-backward-regexp re nil t)
- (progn
- (push-mark (match-end 0))
- (unless point-first (exchange-point-and-mark))
- (mc/create-fake-cursor-at-point))
- (error "no more found backward")))))
- (if (> (mc/num-cursors) 1)
- (multiple-cursors-mode 1)
- (multiple-cursors-mode 0)))
+ (if (region-active-p)
+ (if (< arg 0)
+ (mc/remove-fake-cursor (mc/furthest-cursor-before-point))
+ (mc/mark-more-like-this (= arg 0) 'backwards))
+ (mc/mark-lines arg 'backwards))
+ (mc/maybe-multiple-cursors-mode))
+
+(defun mc/mark-lines (num-lines direction)
+ (dotimes (i num-lines)
+ (mc/create-fake-cursor-at-point)
+ (ecase direction
+ (forwards (loop do (next-line 1 nil)
+ while (mc/all-fake-cursors (point) (1+ (point)))))
+ (backwards (loop do (previous-line 1 nil)
+ while (mc/all-fake-cursors (point) (1+ (point))))))))
+
+;;;###autoload
+(defun mc/mark-next-lines (arg)
+ (interactive "p")
+ (mc/mark-lines arg 'forwards)
+ (mc/maybe-multiple-cursors-mode))
+
+;;;###autoload
+(defun mc/mark-previous-lines (arg)
+ (interactive "p")
+ (mc/mark-lines arg 'backwards)
+ (mc/maybe-multiple-cursors-mode))
;;;###autoload
(defun mc/unmark-next-like-this (arg)
diff --git a/multiple-cursors-core.el b/multiple-cursors-core.el
index 387f7ea..3874231 100644
--- a/multiple-cursors-core.el
+++ b/multiple-cursors-core.el
@@ -49,12 +49,15 @@
(setq buffer-undo-list ;; otherwise add a function to activate this
cursor
(cons (cons 'apply (cons 'activate-cursor-for-undo (list id)))
buffer-undo-list)))))
+(defun mc/all-fake-cursors (&optional start end)
+ (remove-if-not 'mc/fake-cursor-p
+ (overlays-in (or start (point-min))
+ (or end (point-max)))))
+
(defmacro mc/for-each-fake-cursor (&rest forms)
"Runs the body for each fake cursor, bound to the name cursor"
- `(mapc #'(lambda (cursor)
- (when (mc/fake-cursor-p cursor)
- ,@forms))
- (overlays-in (point-min) (point-max))))
+ `(mapc #'(lambda (cursor) ,@forms)
+ (mc/all-fake-cursors)))
(defmacro mc/save-excursion (&rest forms)
"Saves and restores all the state that multiple-cursors cares about."
- [nongnu] elpa/multiple-cursors dc22766 108/434: Macros must be defined before they are used to be expanded properly, (continued)
- [nongnu] elpa/multiple-cursors dc22766 108/434: Macros must be defined before they are used to be expanded properly, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 7a655b0 117/434: Disable emacs-snapshot tests until it is in order., ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 067063a 118/434: Split multiline kill-ring entry over cursors when num lines match, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors bdc4d9a 124/434: Add some more commands to default run-once/run-for-all lists., ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 0f54f98 133/434: Bump to 1.1.1 for bugfix, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors a0f771f 151/434: Include interactive commands for deselecting prev/next, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 8a12e97 148/434: Mention region-bindings-mode in README, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 19b1a83 160/434: Refactor mc/first-cursor-after and mc/last-cursor-before to not use extreme., ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 9ac7675 155/434: Added tests for mc/cycle-forward and mc/cycle-backward with their new looping behaviour, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors dce196c 167/434: Merge pull request #28 from gvol/master, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors c3b2d84 164/434: Merge pull request #23 from segv/master,
ELPA Syncer <=
- [nongnu] elpa/multiple-cursors be4067d 169/434: Fixed mode-line not showing up, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 2345958 260/434: Run ecukes tests in --no-win mode, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 49027c6 262/434: Add basic tests for 'mc/mark-all-dwim', ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 61388fe 263/434: Add 'mark-all-dwim' tests for selection, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors bf4b0c6 266/434: Refactor mark-dwim tests to share a common background, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 9f91a04 267/434: Add 'mc/mark-all-dwim' to README, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 2682e48 285/434: Merge pull request #116 from gvol/master, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 5fead7d8 286/434: Update README with @gvol contribution., ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 238fb97 291/434: Add edge case scenarios which test behavior of mc/cycle-forward and mc/cycle-backward, ELPA Syncer, 2021/08/07
- [nongnu] elpa/multiple-cursors 7b4dd88 295/434: Merge pull request #129 from jistr/readme_typo, ELPA Syncer, 2021/08/07