66 Commits

Author SHA1 Message Date
Magnar Sveen d17c89e418 Release 1.3.0 2013-09-06 22:21:57 +02:00
Magnar Sveen 65c0c0c6fe Merge pull request #104 from mathrick/mark-all-dwim
Add new command, mark-all-dwim
2013-09-06 12:57:31 -07:00
Maciej Katafiasz ec4781394c Derp, multiple cursors means > 1, not > 0. 2013-09-06 19:44:31 +02:00
Maciej Katafiasz ad79ad8b52 Mention only 'mc/mark-all-dwim' in README to prevent confusing redundancy 2013-09-06 14:53:35 +02:00
Maciej Katafiasz 18d858f0de Fall straight through in 'mc/mark-all-dwim' if multiple cursors are already active, as that means we can't sensibly edit lines or mark all in region 2013-09-06 14:52:16 +02:00
Magnar Sveen 68dfa461f1 Merge pull request #109 from mathrick/fix-mark-all-in-region-hang
Guard against empty search pattern in 'mc/mark-all-in-region', otherwise...
2013-09-06 03:09:25 -07:00
Maciej Katafiasz a86daa79ce Guard with 'if' rather than defun*/return-from 2013-09-06 09:33:37 +02:00
Maciej Katafiasz 8dfe725c4f Abort immediately when empty search pattern is passed to 'mc/mark-all-in-region' 2013-09-05 23:53:59 +02:00
Magnar Sveen d8c5227443 Merge pull request #103 from mathrick/compat-24.2
Add gnu repo to Cask, which is needed for cl-lib on Emacs <24.3
2013-09-05 11:52:11 -07:00
Maciej Katafiasz 9f91a0455d Add 'mc/mark-all-dwim' to README 2013-09-05 18:51:51 +02:00
Maciej Katafiasz bf4b0c669b Refactor mark-dwim tests to share a common background 2013-09-05 18:42:16 +02:00
Maciej Katafiasz 45ed43e1f8 Test edit-lines functionality in 'mc/mark-all-dwim' 2013-09-05 18:22:12 +02:00
Maciej Katafiasz af66635a05 Make 'mc/mark-all-dwim' into 'mc/edit-lines' if prefix arg is passed 2013-09-05 18:16:39 +02:00
Maciej Katafiasz 61388fedef Add 'mark-all-dwim' tests for selection 2013-09-05 18:07:52 +02:00
Maciej Katafiasz 49027c6717 Add basic tests for 'mc/mark-all-dwim' 2013-09-05 17:51:19 +02:00
Maciej Katafiasz 5e879f9b5c Guard against empty search pattern in 'mc/mark-all-in-region', otherwise it will enter an infinite loop 2013-09-05 17:42:36 +02:00
Magnar Sveen 23459589eb Run ecukes tests in --no-win mode
Fixes #108
2013-09-05 14:00:21 +02:00
Magnar Sveen e28090d635 Merge pull request #106 from porterjamesj/patch-1
Update README to note that there is a mode allowing search in multiple-c...
2013-09-03 21:48:25 -07:00
James Porter be7905d9e0 Update README to note that there is a mode allowing search in multiple-cursors. 2013-09-03 21:17:18 -04:00
Maciej Katafiasz a37403178f Add gnu repo to Cask, which is needed for cl-lib on Emacs <24.3 2013-08-30 22:38:37 +02:00
Maciej Katafiasz 45c6cd0be4 Add mc/mark-all-dwim 2013-08-30 22:36:01 +02:00
Magnar Sveen 186cb3b63f Release 1.2.3 2013-08-24 20:39:50 +02:00
Magnar Sveen c94eca57ae Fix broken let binding 2013-08-24 20:39:50 +02:00
Magnar Sveen 725369c445 Merge pull request #97 from knu/fix-mc-mark-pop-doc
Fix the doc string of mc/mark-pop, which was not updated after a copy.
2013-08-20 23:18:36 -07:00
Akinori MUSHA e8d734452e Fix the doc string of mc/mark-pop, which was not updated after a copy. 2013-08-21 12:55:22 +09:00
Magnar Sveen 398cc9e466 Merge pull request #92 from knu/mark_by_logical_lines
mc/mark-lines: Mark by logical lines.
2013-08-15 21:10:47 -07:00
Magnar Sveen 6745142d87 Move from Carton to Cask 2013-08-11 21:18:04 +02:00
Magnar Sveen 47e03d54f4 Release 1.2.2 2013-08-11 20:51:37 +02:00
Magnar Sveen 39f17258b8 Add support for god-mode
@chrisdone
2013-08-11 20:51:09 +02:00
Akinori MUSHA 2186e1b6e5 mc/mark-lines: Mark by logical lines. 2013-08-01 17:00:03 +09:00
Magnar Sveen 66ceb0b0d4 Revert cursor specific pre- & post-command-hooks
- makes for problems with global post-command-hooks
 - doesn't really solve the problem they set out to do
2013-07-30 22:11:47 +02:00
Magnar Sveen 6cff0c2ebd Add pre- & post-command-hook to be cursor specific 2013-07-14 14:07:07 +02:00
Magnar Sveen 4c293c46fd Disable snapshot CI 2013-07-11 10:34:22 +02:00
Magnar Sveen 754de4e63b Backport set-temporary-overlay-map to emacs <24.3
Fixes #88
2013-07-11 09:14:06 +02:00
Magnar Sveen 1cb894d119 Add more mc-specific commands to the run-once list
#84
2013-06-08 10:31:49 +02:00
Magnar Sveen cc45842384 Improved mc/mark-more-like-this-extended
- support for terminal
 - more instructive message
 - keymap that can be rebound

Fixes #84
2013-06-07 23:18:19 +02:00
Magnar Sveen 94af07453d Add some readability enhancing step definitions 2013-06-07 08:03:05 +02:00
Magnar Sveen cb848b2a39 Add @smithzvk to contributors list
Closes #80
2013-05-27 05:52:38 +02:00
Magnar Sveen 474838666a Make mc/mark-pop only run once per invocation 2013-05-27 05:51:59 +02:00
Zach Kost-Smith 53db250b43 Added a mark-pop.feature file. 2013-05-26 16:08:21 -05:00
Zach Kost-Smith 75df47fc4a Added mention of mc/mark-pop to README.md 2013-05-26 16:07:27 -05:00
Zach Kost-Smith 4535033952 Added a new function mc/mark-pop that sets cursors by popping marks off the mark stack. 2013-05-26 14:34:58 -05:00
Magnar Sveen 69c99618f9 Use Carton for dev dependencies 2013-05-18 08:16:23 +02:00
Magnar Sveen 7a236d174e Add flyspell-mode to unsupported minor modes 2013-05-08 11:00:42 +02:00
Magnar Sveen 374244b66e Add support for C-s and C-r when phi-search is installed 2013-05-08 11:00:10 +02:00
Magnar Sveen 8b91e4788c Add py-electric-backspace to run-for-all list
- backspace = no in the prompt, causing people not to notice the prompt
2013-04-08 08:42:23 +02:00
Magnar Sveen bf0177205e Use phi-search for C-s in mc-mode when available. 2013-03-28 19:41:08 +01:00
Magnar Sveen 6e159238b2 Use uninterned symbols in macros to avoid surprising local vars 2013-03-21 10:17:50 +01:00
Magnar Sveen 9dac934bce Fix scrolling behavior in Emacs 24. 2013-03-21 10:09:41 +01:00
Magnar Sveen ccb42b5d70 Inline defun for better readability. 2013-03-15 20:21:34 +01:00
Magnar Sveen 8a53db8a39 Merge pull request #64 from tarsius/master
add .nosearch to directory with bundled libraries
2013-03-12 13:52:35 -07:00
Jonas Bernoulli 72ba43a08e add .nosearch to directory with bundled libraries
And move ert.el to that directory.
2013-03-12 21:40:43 +01:00
Magnar Sveen 16589a5af2 Update README.md 2013-03-10 07:58:04 +01:00
Magnar Sveen 980a8808dd Merge pull request #63 from tkf/select-thing-at-point
Automatically select word/symbol
2013-03-09 22:54:22 -08:00
Magnar Sveen ed18fa49c1 Merge pull request #62 from tkf/export-ECUKES_EMACS
Export $ECUKES_EMACS
2013-03-09 22:41:12 -08:00
Takafumi Arakaki 1cdd73037f Automatically select word/symbol 2013-03-10 06:53:53 +01:00
Takafumi Arakaki aa9a1ece7b Add failing scenarios for mark-all-symbols/words 2013-03-10 06:52:12 +01:00
Takafumi Arakaki 25dd14d350 Add more scenarios for mark-all-*-like-this 2013-03-10 06:49:25 +01:00
Takafumi Arakaki 373dcbe002 Add a scenario for mc/mark-all-symbols-like-this 2013-03-10 06:44:18 +01:00
Takafumi Arakaki d24ddc53ea Default ECUKES_EMACS to $EMACS
Otherwise, $EMACS set on .travis.yml is not used in test.
2013-03-10 06:17:30 +01:00
Takafumi Arakaki 5c60757080 export ECUKES_EMACS in run-travis-ci.sh 2013-03-10 06:12:07 +01:00
Magnar Sveen a6e0ccb22f mc/add-cursor-on-click should not run per cursor
Fixes #60
2013-02-26 21:38:26 +01:00
Magnar Sveen 0ee76bfad1 Add mc/add-cursor-on-click 2013-02-20 07:05:18 +01:00
Magnar Sveen e7a5fe61c4 Release 1.2.1 2013-02-11 07:32:09 +01:00
Magnar Sveen 641eb680ca Can use mc/reverse-regions w/o region or cursors
- will flip sexp at point with the one below it
2013-02-11 07:29:17 +01:00
Magnar Sveen 16add89d29 Bugfix for sort/reverse regions w/similar contents 2013-02-11 07:28:26 +01:00
26 changed files with 748 additions and 3076 deletions
+1
View File
@@ -0,0 +1 @@
elpa
-6
View File
@@ -1,6 +0,0 @@
[submodule "util/ecukes"]
path = util/ecukes
url = git://github.com/rejeep/ecukes.git
[submodule "util/espuds"]
path = util/espuds
url = git://github.com/rejeep/espuds.git
+4 -3
View File
@@ -12,9 +12,10 @@ before_install:
sudo apt-get install -qq sudo apt-get install -qq
emacs24 emacs24-el emacs24-common-non-dfsg; emacs24 emacs24-el emacs24-common-non-dfsg;
fi fi
- curl -fsSkL https://raw.github.com/rejeep/cask.el/master/go | sh
- export PATH="/home/travis/.cask/bin:$PATH"
- cask
env: env:
- EMACS=emacs - EMACS=emacs24 TAGS=""
- EMACS=emacs24
- EMACS=emacs-snapshot
script: script:
./run-travis-ci.sh ./run-travis-ci.sh
+9
View File
@@ -0,0 +1,9 @@
(source gnu)
(source melpa)
(package-file "multiple-cursors.el")
(development
(depends-on "ecukes")
(depends-on "espuds")
(depends-on "wrap-region"))
+35 -6
View File
@@ -46,6 +46,16 @@ You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.co
- `mc/mark-previous-word-like-this`: Like `mc/mark-previous-like-this` but only for whole words. - `mc/mark-previous-word-like-this`: Like `mc/mark-previous-like-this` but only for whole words.
- `mc/mark-previous-symbol-like-this`: Like `mc/mark-previous-like-this` but only for whole symbols. - `mc/mark-previous-symbol-like-this`: Like `mc/mark-previous-like-this` but only for whole symbols.
- `mc/mark-more-like-this-extended`: Use arrow keys to quickly mark/skip next/previous occurances. - `mc/mark-more-like-this-extended`: Use arrow keys to quickly mark/skip next/previous occurances.
- `mc/add-cursor-on-click`: Bind to a mouse event to add cursors by clicking. See tips-section.
- `mc/pop-mark`: Set a cursor at the current point and move to the next (different) position on the mark stack. This allows for fine grained control over the placement of cursors.
### Juggle around with the current cursors
- `mc/unmark-next-like-this`: Remove the cursor furthest down in the buffer.
- `mc/unmark-previous-like-this`: Remove the cursor furthest up in the buffer.
- `mc/skip-to-next-like-this`: Remove the cursor furthest down, marking the next occurance down.
- `mc/skip-to-previous-like-this`: Remove the cursor furthest up, marking the next occurance up.
- `mc/mark-next-like-this-extended`: Temporarily bind the arrow keys to mark/unmark/skip cursors.
### Mark many occurrences ### Mark many occurrences
@@ -59,7 +69,7 @@ You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.co
- `mc/mark-all-like-this-in-defun`: Marks all parts of the current defun that matches the current region. - `mc/mark-all-like-this-in-defun`: Marks all parts of the current defun that matches the current region.
- `mc/mark-all-words-like-this-in-defun`: Like `mc/mark-all-like-this-in-defun` but only for whole words. - `mc/mark-all-words-like-this-in-defun`: Like `mc/mark-all-like-this-in-defun` but only for whole words.
- `mc/mark-all-symbols-like-this-in-defun`: Like `mc/mark-all-like-this-in-defun` but only for whole symbols. - `mc/mark-all-symbols-like-this-in-defun`: Like `mc/mark-all-like-this-in-defun` but only for whole symbols.
- `mc/mark-all-like-this-dwim`: Tries to be smart about marking everything you want. Can be pressed multiple times. - `mc/mark-all-dwim`: Tries to be smart about marking everything you want. Can be pressed multiple times.
### Special ### Special
@@ -89,12 +99,27 @@ You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.co
from the kill-ring of main cursor. To yank from the kill-rings of from the kill-ring of main cursor. To yank from the kill-rings of
every cursor use yank-rectangle, normally found at C-x r y. every cursor use yank-rectangle, normally found at C-x r y.
- You can use `mc/reverse-regions` with nothing selected and just one cursor.
It will then flip the sexp at point and the one below it.
- If you would like to keep the global bindings clean, and get custom keybindings - If you would like to keep the global bindings clean, and get custom keybindings
when the region is active, you can try [region-bindings-mode](https://github.com/fgallina/region-bindings-mode). when the region is active, you can try [region-bindings-mode](https://github.com/fgallina/region-bindings-mode).
BTW, I highly recommend adding `mc/mark-next-like-this` to a key binding that's BTW, I highly recommend adding `mc/mark-next-like-this` to a key binding that's
right next to the key for `er/expand-region`. right next to the key for `er/expand-region`.
### Binding mouse events
To override a mouse event, you will likely have to also unbind the
`down-mouse` part of the event. Like this:
(global-unset-key (kbd "M-<down-mouse-1>"))
(global-set-key (kbd "M-<mouse-1>") 'mc/add-cursor-on-click)
Or you can do like me and find an unused, but less convenient, binding:
(global-set-key (kbd "C-S-<mouse-1>") 'mc/add-cursor-on-click)
## Unknown commands ## Unknown commands
Multiple-cursors uses two lists of commands to know what to do: the run-once list Multiple-cursors uses two lists of commands to know what to do: the run-once list
@@ -111,7 +136,7 @@ the location with:
## Known limitations ## Known limitations
* isearch-forward and isearch-backward aren't supported with multiple cursors. * isearch-forward and isearch-backward aren't supported with multiple cursors.
You should feel free to add a simplified version that can work with it. If you want this functionality, you can use [phi-search](https://github.com/zk-phi/phi-search).
* Commands run with `M-x` won't be repeated for all cursors. * Commands run with `M-x` won't be repeated for all cursors.
* All key bindings that refer to lambdas are always run for all cursors. If you * All key bindings that refer to lambdas are always run for all cursors. If you
need to limit it, you will have to give it a name. need to limit it, you will have to give it a name.
@@ -127,21 +152,25 @@ You'll find the repo at:
https://github.com/magnars/multiple-cursors.el https://github.com/magnars/multiple-cursors.el
To fetch the test dependencies: To fetch the test dependencies, install
[cask](https://github.com/rejeep/cask.el) if you haven't already,
then:
$ cd /path/to/multiple-cursors $ cd /path/to/multiple-cursors
$ git submodule update --init $ cask
Run the tests with: Run the tests with:
$ ./util/ecukes/ecukes --graphical $ ./run-tests.sh
## Contributors ## Contributors
* [Takafumi Arakaki](https://github.com/tkf) made .mc-lists.el diff friendly * [Takafumi Arakaki](https://github.com/tkf) has contributed several small improvements
* [Marco Baringer](https://github.com/segv) contributed looping to mc/cycle and adding cursors without region for mark-more. * [Marco Baringer](https://github.com/segv) contributed looping to mc/cycle and adding cursors without region for mark-more.
* [Ivan Andrus](https://github.com/gvol) added showing number of cursors in mode-line * [Ivan Andrus](https://github.com/gvol) added showing number of cursors in mode-line
* [Fuco](https://github.com/Fuco1) added the first version of `mc/mark-all-like-this-dwim` * [Fuco](https://github.com/Fuco1) added the first version of `mc/mark-all-like-this-dwim`
* [Zach Kost-Smith](https://github.com/smithzvk) added `mc/mark-pop`
* [Maciej Katafiasz](https://github.com/mathrick) added `mc/mark-all-dwim`
Thanks! Thanks!
+61 -9
View File
@@ -1,13 +1,16 @@
Feature: Mark all do-what-I-mean Feature: Mark all do-what-I-mean
Scenario: Mark symbols in defun Background:
Given I turn on emacs-lisp-mode Given I turn on emacs-lisp-mode
And I turn on delete-selection-mode And I turn on delete-selection-mode
And I insert: And I insert:
""" """
(defun abc (ghi) (message ghi)) (defun abc (ghi) (message ghi))
(defun def (ghi) (message some-other-ghi)) (defun def (ghi) (message some-other-ghi))
""" """
Scenario: Mark symbols in defun
When I go to the end of the word "abc" When I go to the end of the word "abc"
And I press "M-f" And I press "M-f"
And I press "M-$" And I press "M-$"
@@ -17,15 +20,17 @@ Feature: Mark all do-what-I-mean
(defun abc (hmm) (message hmm)) (defun abc (hmm) (message hmm))
(defun def (ghi) (message some-other-ghi)) (defun def (ghi) (message some-other-ghi))
""" """
When I press "C-g"
And I go to the front of the word "hmm"
And I press "C-$"
And I type "foo"
Then I should see:
"""
(defun abc (foo) (message foo))
(defun def (ghi) (message some-other-ghi))
"""
Scenario: Mark all symbols by pressing twice Scenario: Mark all symbols by pressing twice
Given I turn on emacs-lisp-mode
And I turn on delete-selection-mode
And I insert:
"""
(defun abc (ghi) (message ghi))
(defun def (ghi) (message ghi))
"""
When I go to the end of the word "abc" When I go to the end of the word "abc"
And I press "M-f" And I press "M-f"
And I press "M-$" And I press "M-$"
@@ -34,5 +39,52 @@ Feature: Mark all do-what-I-mean
Then I should see: Then I should see:
""" """
(defun abc (hmm) (message hmm)) (defun abc (hmm) (message hmm))
(defun def (hmm) (message hmm)) (defun def (hmm) (message some-other-hmm))
"""
When I press "C-g"
And I press "M->"
And I insert:
"""
(defun def (hmm-hmm) (message hmm))
"""
And I go to the front of the word "hmm"
And I press "C-$"
And I press "C-$"
And I type "humm"
Then I should see:
"""
(defun abc (humm) (message humm))
(defun def (humm) (message some-other-humm))
(defun def (humm-humm) (message humm))
"""
Scenario: Mark dwim from selection
When I press "M-<"
And I press "S-M->"
And I press "C-$ ghi RET"
And I type "xyz"
Then I should see:
"""
(defun abc (xyz) (message xyz))
(defun def (xyz) (message some-other-xyz))
"""
When I press "C-g"
And I go to the front of the word "xyz"
And I press "C-M-SPC"
And I press "C-$"
And I type "foo"
Then I should see:
"""
(defun abc (foo) (message foo))
(defun def (xyz) (message some-other-xyz))
"""
When I press "C-g"
And I press "M-<"
And I press "S-M->"
And I press "C-u C-$"
And I type ";;"
Then I should see:
"""
;;(defun abc (foo) (message foo))
;;(defun def (xyz) (message some-other-xyz))
""" """
+88
View File
@@ -0,0 +1,88 @@
Feature: Popping cursors off of the mark stack
Scenario: Single pop
Given I turn off transient-mark-mode
And I insert:
"""
hello
there
"""
And I go to the front of the word "hello"
And I set the mark
And I go to the front of the word "there"
And I press "M-x mc/mark-pop"
Then I should have 2 cursors
Scenario: Multiple pops
Given I turn off transient-mark-mode
And I insert:
"""
hello
there, my friend
"""
And I go to the front of the word "hello"
And I set the mark
And I go to the front of the word "my"
And I set the mark
And I go to the front of the word "friend"
And I press "M-x mc/mark-pop"
And I press "M-x mc/mark-pop"
Then I should have 3 cursors
Scenario: Discard identical mark and point
Given I turn off transient-mark-mode
And I insert:
"""
hello
there, my friend
"""
And I go to the front of the word "hello"
And I set the mark
And I go to the front of the word "my"
And I set the mark
And I go to the front of the word "friend"
And I set the mark
And I press "M-x mc/mark-pop"
And I press "M-x mc/mark-pop"
Then I should have 3 cursors
Scenario: Changing the text
Given I turn off transient-mark-mode
And I insert:
"""
hello
there, my friend
"""
And I go to the front of the word "hello"
And I set the mark
And I go to the front of the word "my"
And I set the mark
And I go to the front of the word "friend"
And I press "M-x mc/mark-pop"
And I press "M-x mc/mark-pop"
And I type "!"
Then I should see:
"""
!hello
there, !my !friend
"""
Scenario: With transient-mark-mode
And I insert:
"""
hello
there, my friend
"""
And I go to the front of the word "hello"
And I press "C-@ C-@"
And I go to the front of the word "my"
And I press "C-@ C-@"
And I go to the front of the word "friend"
And I press "M-x mc/mark-pop"
And I press "M-x mc/mark-pop"
And I type "!"
Then I should see:
"""
!hello
there, !my !friend
"""
+137
View File
@@ -0,0 +1,137 @@
Feature: Mark things
Scenario: Mark all symbols like this with select
Given I turn on emacs-lisp-mode
And I turn on delete-selection-mode
And I insert:
"""
(defun abc (ghi) (message ghi))
(defun def (ghi) (message some-other-ghi))
"""
When I select "ghi"
And I mark all symbols like this
And I type "hmm"
Then I should see:
"""
(defun abc (hmm) (message hmm))
(defun def (hmm) (message some-other-ghi))
"""
Scenario: Mark all words like this with select
Given I turn on emacs-lisp-mode
And I turn on delete-selection-mode
And I insert:
"""
(defun abc (ghi) (message ghi))
(defun def (ghi) (message some-other-ghi))
"""
When I select "ghi"
And I mark all words like this
And I type "hmm"
Then I should see:
"""
(defun abc (hmm) (message hmm))
(defun def (hmm) (message some-other-hmm))
"""
Scenario: Mark all symbols like this in defun with select
Given I turn on emacs-lisp-mode
And I turn on delete-selection-mode
And I insert:
"""
(defun abc (ghi) (message ghi))
(defun def (ghi) (message some-other-ghi))
"""
When I select "ghi"
And I mark all symbols like this in defun
And I type "hmm"
Then I should see:
"""
(defun abc (hmm) (message hmm))
(defun def (ghi) (message some-other-ghi))
"""
Scenario: Mark all words like this in defun with select
Given I turn on emacs-lisp-mode
And I turn on delete-selection-mode
And I insert:
"""
(defun abc (ghi) (message ghi))
(defun def (ghi) (message some-other-ghi))
"""
When I select "ghi"
And I mark all words like this in defun
And I type "hmm"
Then I should see:
"""
(defun abc (hmm) (message hmm))
(defun def (ghi) (message some-other-ghi))
"""
Scenario: Mark all symbols like this with no select
Given I turn on emacs-lisp-mode
And I turn on delete-selection-mode
And I insert:
"""
(defun abc (ghi) (message ghi))
(defun def (ghi) (message some-other-ghi))
"""
When I go to word "ghi"
And I mark all symbols like this
And I type "hmm"
Then I should see:
"""
(defun abc (hmm) (message hmm))
(defun def (hmm) (message some-other-ghi))
"""
Scenario: Mark all words like this with no select
Given I turn on emacs-lisp-mode
And I turn on delete-selection-mode
And I insert:
"""
(defun abc (ghi) (message ghi))
(defun def (ghi) (message some-other-ghi))
"""
When I go to word "ghi"
And I mark all words like this
And I type "hmm"
Then I should see:
"""
(defun abc (hmm) (message hmm))
(defun def (hmm) (message some-other-hmm))
"""
Scenario: Mark all symbols like this in defun with no select
Given I turn on emacs-lisp-mode
And I turn on delete-selection-mode
And I insert:
"""
(defun abc (ghi) (message ghi))
(defun def (ghi) (message some-other-ghi))
"""
When I go to word "ghi"
And I mark all symbols like this in defun
And I type "hmm"
Then I should see:
"""
(defun abc (hmm) (message hmm))
(defun def (ghi) (message some-other-ghi))
"""
Scenario: Mark all words like this in defun with no select
Given I turn on emacs-lisp-mode
And I turn on delete-selection-mode
And I insert:
"""
(defun abc (ghi) (message ghi))
(defun def (ghi) (message some-other-ghi))
"""
When I go to word "ghi"
And I mark all words like this in defun
And I type "hmm"
Then I should see:
"""
(defun abc (hmm) (message hmm))
(defun def (ghi) (message some-other-ghi))
"""
+2 -2
View File
@@ -115,7 +115,7 @@ Feature: Multiple cursors core
And I go to the front of the word "text" And I go to the front of the word "text"
And I press "C-SPC" And I press "C-SPC"
And I press "M-f" And I press "M-f"
And I press "C->" And I mark next like this
And I type "!" And I type "!"
Then I should see "This ! contains the word ! twice" Then I should see "This ! contains the word ! twice"
@@ -124,7 +124,7 @@ Feature: Multiple cursors core
And I insert "This text contains the word text twice" And I insert "This text contains the word text twice"
And I go to the front of the word "text" And I go to the front of the word "text"
And I press "C-M-SPC" And I press "C-M-SPC"
And I press "C->" And I mark next like this
And I press "C-g" And I press "C-g"
And I type "(" And I type "("
Then I should see "This (text contains the word (text twice" Then I should see "This (text contains the word (text twice"
@@ -1,7 +1,41 @@
(When "^I mark next like this$"
(lambda () (call-interactively 'mc/mark-next-like-this)))
(When "^I mark previous like this$"
(lambda () (call-interactively 'mc/mark-previous-like-this)))
(When "^I mark all like this$"
(lambda () (call-interactively 'mc/mark-all-like-this)))
(When "^I mark all like this dwim$"
(lambda () (call-interactively 'mc/mark-all-like-this-dwim)))
(When "^I mark all in region$"
(lambda () (call-interactively 'mc/mark-all-in-region)))
(When "^I insert numbers$"
(lambda () (call-interactively 'mc/insert-numbers)))
(When "^I reverse regions$"
(lambda () (call-interactively 'mc/reverse-regions)))
(When "^I sort regions$"
(lambda () (call-interactively 'mc/sort-regions)))
(When "^I edit lines$"
(lambda () (call-interactively 'mc/edit-lines)))
(When "^I set rectangular region anchor$"
(lambda () (call-interactively 'set-rectangular-region-anchor)))
(And "^delete-selection-mode is active$" (And "^delete-selection-mode is active$"
(lambda () (lambda ()
(delete-selection-mode 1))) (delete-selection-mode 1)))
(Given "^I turn off transient-mark-mode$"
(lambda ()
(transient-mark-mode -1)))
(Then "^I should have \\([0-9]+\\) cursors$" (Then "^I should have \\([0-9]+\\) cursors$"
(lambda (num) (lambda (num)
(let ((actual (mc/num-cursors))) (let ((actual (mc/num-cursors)))
@@ -95,3 +129,11 @@
(assert search nil "The text '%s' was not found in the current buffer." text)) (assert search nil "The text '%s' was not found in the current buffer." text))
(set-mark (point)) (set-mark (point))
(re-search-forward text))) (re-search-forward text)))
(When "^I mark all \\(.+\\)$"
(lambda (rest)
(let ((func (intern (mapconcat 'identity
(cons "mc/mark-all"
(split-string rest))
"-"))))
(call-interactively func))))
+1
View File
@@ -24,6 +24,7 @@
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this) (global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
(global-set-key (kbd "M-!") 'mc/mark-all-like-this) (global-set-key (kbd "M-!") 'mc/mark-all-like-this)
(global-set-key (kbd "M-$") 'mc/mark-all-like-this-dwim) (global-set-key (kbd "M-$") 'mc/mark-all-like-this-dwim)
(global-set-key (kbd "C-$") 'mc/mark-all-dwim)
(global-set-key (kbd "M-#") 'mc/mark-all-in-region) (global-set-key (kbd "M-#") 'mc/mark-all-in-region)
(global-set-key (kbd "H-0") 'mc/insert-numbers) (global-set-key (kbd "H-0") 'mc/insert-numbers)
(global-set-key (kbd "H-1") 'mc/reverse-regions) (global-set-key (kbd "H-1") 'mc/reverse-regions)
+2 -4
View File
@@ -57,16 +57,14 @@ line point is on."
"Add one cursor to the end of each line in the active region." "Add one cursor to the end of each line in the active region."
(interactive) (interactive)
(mc/edit-lines) (mc/edit-lines)
(mc/execute-command-for-all-fake-cursors 'end-of-line) (mc/execute-command-for-all-cursors 'end-of-line))
(end-of-line))
;;;###autoload ;;;###autoload
(defun mc/edit-beginnings-of-lines () (defun mc/edit-beginnings-of-lines ()
"Add one cursor to the beginning of each line in the active region." "Add one cursor to the beginning of each line in the active region."
(interactive) (interactive)
(mc/edit-lines) (mc/edit-lines)
(mc/execute-command-for-all-fake-cursors 'beginning-of-line) (mc/execute-command-for-all-cursors 'beginning-of-line))
(beginning-of-line))
(provide 'mc-edit-lines) (provide 'mc-edit-lines)
+172 -50
View File
@@ -173,9 +173,9 @@ With zero ARG, skip the last one and mark next."
(dotimes (i num-lines) (dotimes (i num-lines)
(mc/create-fake-cursor-at-point) (mc/create-fake-cursor-at-point)
(ecase direction (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))))) 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)))))))) while (mc/all-fake-cursors (point) (1+ (point))))))))
;;;###autoload ;;;###autoload
@@ -191,17 +191,29 @@ With zero ARG, skip the last one and mark next."
(mc/maybe-multiple-cursors-mode)) (mc/maybe-multiple-cursors-mode))
;;;###autoload ;;;###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." "Deselect next part of the buffer matching the currently active region."
(interactive) (interactive)
(mc/mark-next-like-this -1)) (mc/mark-next-like-this -1))
;;;###autoload ;;;###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." "Deselect prev part of the buffer matching the currently active region."
(interactive) (interactive)
(mc/mark-previous-like-this -1)) (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 ;;;###autoload
(defun mc/mark-all-like-this () (defun mc/mark-all-like-this ()
"Find and mark all the parts of the buffer matching the currently active region" "Find and mark all the parts of the buffer matching the currently active region"
@@ -225,15 +237,28 @@ With zero ARG, skip the last one and mark next."
(multiple-cursors-mode 1) (multiple-cursors-mode 1)
(multiple-cursors-mode 0))) (multiple-cursors-mode 0)))
(defun mc--select-thing-at-point (thing)
(let ((bound (bounds-of-thing-at-point thing)))
(when bound
(set-mark (car bound))
(goto-char (cdr bound))
bound)))
(defun mc--select-thing-at-point-or-bark (thing)
(unless (or (region-active-p) (mc--select-thing-at-point thing))
(error "Mark a region or set cursor on a %s." thing)))
;;;###autoload ;;;###autoload
(defun mc/mark-all-words-like-this () (defun mc/mark-all-words-like-this ()
(interactive) (interactive)
(mc--select-thing-at-point-or-bark 'word)
(let ((mc/enclose-search-term 'words)) (let ((mc/enclose-search-term 'words))
(mc/mark-all-like-this))) (mc/mark-all-like-this)))
;;;###autoload ;;;###autoload
(defun mc/mark-all-symbols-like-this () (defun mc/mark-all-symbols-like-this ()
(interactive) (interactive)
(mc--select-thing-at-point-or-bark 'symbol)
(let ((mc/enclose-search-term 'symbols)) (let ((mc/enclose-search-term 'symbols))
(mc/mark-all-like-this))) (mc/mark-all-like-this)))
@@ -243,6 +268,9 @@ With zero ARG, skip the last one and mark next."
(interactive "r") (interactive "r")
(let ((search (read-from-minibuffer "Mark all in region: ")) (let ((search (read-from-minibuffer "Mark all in region: "))
(case-fold-search nil)) (case-fold-search nil))
(if (string= search "")
(message "Mark aborted")
(progn
(mc/remove-fake-cursors) (mc/remove-fake-cursors)
(goto-char beg) (goto-char beg)
(while (search-forward search end t) (while (search-forward search end t)
@@ -251,57 +279,114 @@ With zero ARG, skip the last one and mark next."
(let ((first (mc/furthest-cursor-before-point))) (let ((first (mc/furthest-cursor-before-point)))
(if (not first) (if (not first)
(error "Search failed for %S" search) (error "Search failed for %S" search)
(mc/pop-state-from-overlay first)))) (mc/pop-state-from-overlay first)))
(if (> (mc/num-cursors) 1) (if (> (mc/num-cursors) 1)
(multiple-cursors-mode 1) (multiple-cursors-mode 1)
(multiple-cursors-mode 0))) (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 ;;;###autoload
(defun mc/mark-more-like-this-extended () (defun mc/mark-more-like-this-extended ()
"Like mark-more-like-this, but then lets you adjust with arrows key. "Like mark-more-like-this, but then lets you adjust with arrows key.
The actual adjustment made depends on the final component of the The adjustments work like this:
key-binding used to invoke the command, with all modifiers removed:
<up> Mark previous like this <up> Mark previous like this and set direction to 'up
<down> Mark next like this <down> Mark next like this and set direction to 'down
<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 If direction is 'up:
as long as the input event read (with all modifiers removed)
is one of the above." <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) (interactive)
(let ((first t) (mc/mmlte--down)
(ev last-command-event) (set-temporary-overlay-map mc/mark-more-like-this-extended-keymap t))
(cmd 'mc/mark-next-like-this)
(arg 1) (defvar mc/mark-more-like-this-extended-direction nil
last echo-keystrokes) "When using mc/mark-more-like-this-extended are we working on the next or previous cursors?")
(while cmd
(let ((base (event-basic-type ev))) (make-variable-buffer-local 'mc/mark-more-like-this-extended)
(cond ((eq base 'left)
(if (eq last 'mc/mark-previous-like-this) (defun mc/mmlte--message ()
(setq cmd last arg 0) (if (eq mc/mark-more-like-this-extended-direction 'up)
(setq cmd 'mc/mark-next-like-this arg -1))) (message "<up> to mark previous, <left> to skip, <right> to remove, <down> to mark next")
((eq base 'up) (message "<down> to mark next, <right> to skip, <left> to remove, <up> to mark previous")))
(setq cmd 'mc/mark-previous-like-this arg 1))
((eq base 'right) (defun mc/mmlte--up ()
(if (eq last 'mc/mark-next-like-this) (interactive)
(setq cmd last arg 0) (mc/mark-previous-like-this 1)
(setq cmd 'mc/mark-previous-like-this arg -1))) (setq mc/mark-more-like-this-extended-direction 'up)
((eq base 'down) (mc/mmlte--message))
(setq cmd 'mc/mark-next-like-this arg 1))
(first (defun mc/mmlte--down ()
(setq cmd 'mc/mark-next-like-this arg 1)) (interactive)
(t (mc/mark-next-like-this 1)
(setq cmd nil)))) (setq mc/mark-more-like-this-extended-direction 'down)
(when cmd (mc/mmlte--message))
(ignore-errors
(funcall cmd arg)) (defun mc/mmlte--left ()
(setq first nil last cmd) (interactive)
(setq ev (read-event "Use arrow keys for more marks: ")))) (if (eq mc/mark-more-like-this-extended-direction 'down)
(push ev unread-command-events))) (mc/unmark-next-like-this)
(mc/skip-to-previous-like-this))
(mc/mmlte--message))
(defun mc/mmlte--right ()
(interactive)
(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) (defvar mc--restrict-mark-all-to-symbols nil)
@@ -314,7 +399,8 @@ With prefix, it behaves the same as original `mc/mark-all-like-this'"
(interactive "P") (interactive "P")
(if arg (if arg
(mc/mark-all-like-this) (mc/mark-all-like-this)
(if (and (mc--no-region-and-in-sgmlish-mode) (if (and (not (use-region-p))
(derived-mode-p 'sgml-mode)
(mc--on-tag-name-p)) (mc--on-tag-name-p))
(mc/mark-sgml-tag-pair) (mc/mark-sgml-tag-pair)
(let ((before (mc/num-cursors))) (let ((before (mc/num-cursors)))
@@ -333,9 +419,26 @@ With prefix, it behaves the same as original `mc/mark-all-like-this'"
(when (<= (mc/num-cursors) before) (when (<= (mc/num-cursors) before)
(mc/mark-all-like-this)))))) (mc/mark-all-like-this))))))
(defun mc--no-region-and-in-sgmlish-mode () (defun mc/mark-all-dwim (arg)
(and (not (use-region-p)) "Tries even harder to guess what you want to mark all of.
(derived-mode-p 'sgml-mode)))
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 () (defun mc--in-defun ()
(bounds-of-thing-at-point 'defun)) (bounds-of-thing-at-point 'defun))
@@ -355,6 +458,7 @@ With prefix, it behaves the same as original `mc/mark-all-like-this'"
(defun mc/mark-all-words-like-this-in-defun () (defun mc/mark-all-words-like-this-in-defun ()
"Mark all words like this in defun." "Mark all words like this in defun."
(interactive) (interactive)
(mc--select-thing-at-point-or-bark 'word)
(if (mc--in-defun) (if (mc--in-defun)
(save-restriction (save-restriction
(widen) (widen)
@@ -366,6 +470,7 @@ With prefix, it behaves the same as original `mc/mark-all-like-this'"
(defun mc/mark-all-symbols-like-this-in-defun () (defun mc/mark-all-symbols-like-this-in-defun ()
"Mark all symbols like this in defun." "Mark all symbols like this in defun."
(interactive) (interactive)
(mc--select-thing-at-point-or-bark 'symbol)
(if (mc--in-defun) (if (mc--in-defun)
(save-restriction (save-restriction
(widen) (widen)
@@ -398,6 +503,23 @@ With prefix, it behaves the same as original `mc/mark-all-like-this'"
(>= (point) beg) (>= (point) beg)
(<= (point) end)))) (<= (point) end))))
;;;###autoload
(defun mc/add-cursor-on-click (event)
"Add a cursor where you click."
(interactive "e")
(mouse-minibuffer-check event)
;; Use event-end in case called from mouse-drag-region.
;; If EVENT is a click, event-end and event-start give same value.
(let ((position (event-end event)))
(if (not (windowp (posn-window position)))
(error "Position not in text area of window"))
(select-window (posn-window position))
(if (numberp (posn-point position))
(save-excursion
(goto-char (posn-point position))
(mc/create-fake-cursor-at-point)))
(mc/maybe-multiple-cursors-mode)))
;;;###autoload ;;;###autoload
(defun mc/mark-sgml-tag-pair () (defun mc/mark-sgml-tag-pair ()
"Mark the tag we're in and its pair for renaming." "Mark the tag we're in and its pair for renaming."
+22
View File
@@ -0,0 +1,22 @@
;;; mc-mark-pop.el --- Pop cursors off of the mark stack
(require 'multiple-cursors-core)
;;;###autoload
(defun mc/mark-pop ()
"Add a cursor at the current point, pop off mark ring and jump
to the popped mark."
(interactive)
;; If the mark happens to be at the current point, just pop that one off.
(while (eql (mark) (point))
(pop-mark))
(mc/create-fake-cursor-at-point)
(exchange-point-and-mark)
(pop-mark)
(mc/maybe-multiple-cursors-mode))
;; A good key binding for this feature is perhaps "C-S-p" ('p' for pop).
(provide 'mc-mark-pop)
;;; mc-mark-pop.el ends here
+13 -8
View File
@@ -48,9 +48,9 @@
(let (strings) (let (strings)
(save-excursion (save-excursion
(mc/for-each-cursor-ordered (mc/for-each-cursor-ordered
(add-to-list 'strings (buffer-substring-no-properties (setq strings (cons (buffer-substring-no-properties
(mc/cursor-beg cursor) (mc/cursor-beg cursor)
(mc/cursor-end cursor))))strings) (mc/cursor-end cursor)) strings))))
(nreverse strings))) (nreverse strings)))
(defvar mc--strings-to-replace nil) (defvar mc--strings-to-replace nil)
@@ -58,7 +58,7 @@
(defun mc--replace-region-strings-1 () (defun mc--replace-region-strings-1 ()
(interactive) (interactive)
(delete-region (region-beginning) (region-end)) (delete-region (region-beginning) (region-end))
(insert (car mc--strings-to-replace)) (save-excursion (insert (car mc--strings-to-replace)))
(setq mc--strings-to-replace (cdr mc--strings-to-replace))) (setq mc--strings-to-replace (cdr mc--strings-to-replace)))
(defun mc--replace-region-strings () (defun mc--replace-region-strings ()
@@ -68,18 +68,23 @@
;;;###autoload ;;;###autoload
(defun mc/reverse-regions () (defun mc/reverse-regions ()
(interactive) (interactive)
(if (not (use-region-p)) (if (not multiple-cursors-mode)
(message "Mark regions to reverse first.") (progn
(mc/mark-next-lines 1)
(mc/reverse-regions)
(multiple-cursors-mode 0))
(unless (use-region-p)
(mc/execute-command-for-all-cursors 'mark-sexp))
(setq mc--strings-to-replace (nreverse (mc--ordered-region-strings))) (setq mc--strings-to-replace (nreverse (mc--ordered-region-strings)))
(mc--replace-region-strings))) (mc--replace-region-strings)))
;;;###autoload ;;;###autoload
(defun mc/sort-regions () (defun mc/sort-regions ()
(interactive) (interactive)
(if (not (use-region-p)) (unless (use-region-p)
(message "Mark regions to sort first.") (mc/execute-command-for-all-cursors 'mark-sexp))
(setq mc--strings-to-replace (sort (mc--ordered-region-strings) 'string<)) (setq mc--strings-to-replace (sort (mc--ordered-region-strings) 'string<))
(mc--replace-region-strings))) (mc--replace-region-strings))
(provide 'mc-separate-operations) (provide 'mc-separate-operations)
;;; mc-separate-operations.el ends here ;;; mc-separate-operations.el ends here
+66 -44
View File
@@ -41,13 +41,14 @@
(defmacro mc/add-fake-cursor-to-undo-list (&rest forms) (defmacro mc/add-fake-cursor-to-undo-list (&rest forms)
"Make sure point is in the right place when undoing" "Make sure point is in the right place when undoing"
`(let ((undo-cleaner (cons 'apply (cons 'deactivate-cursor-after-undo (list id))))) (let ((uc (make-symbol "undo-cleaner")))
(setq buffer-undo-list (cons undo-cleaner buffer-undo-list)) `(let ((,uc (cons 'apply (cons 'deactivate-cursor-after-undo (list id)))))
(setq buffer-undo-list (cons ,uc buffer-undo-list))
,@forms ,@forms
(if (eq undo-cleaner (car buffer-undo-list)) ;; if nothing has been added to the undo-list (if (eq ,uc (car buffer-undo-list)) ;; if nothing has been added to the undo-list
(setq buffer-undo-list (cdr buffer-undo-list)) ;; then pop the cleaner right off again (setq buffer-undo-list (cdr buffer-undo-list)) ;; then pop the cleaner right off again
(setq buffer-undo-list ;; otherwise add a function to activate this cursor (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))))) (cons (cons 'apply (cons 'activate-cursor-for-undo (list id))) buffer-undo-list))))))
(defun mc/all-fake-cursors (&optional start end) (defun mc/all-fake-cursors (&optional start end)
(remove-if-not 'mc/fake-cursor-p (remove-if-not 'mc/fake-cursor-p
@@ -61,35 +62,40 @@
(defmacro mc/save-excursion (&rest forms) (defmacro mc/save-excursion (&rest forms)
"Saves and restores all the state that multiple-cursors cares about." "Saves and restores all the state that multiple-cursors cares about."
`(let ((current-state (mc/store-current-state-in-overlay (let ((cs (make-symbol "current-state")))
`(let ((,cs (mc/store-current-state-in-overlay
(make-overlay (point) (point) nil nil t)))) (make-overlay (point) (point) nil nil t))))
(overlay-put current-state 'type 'original-cursor) (overlay-put ,cs 'type 'original-cursor)
(save-excursion ,@forms) (save-excursion ,@forms)
(mc/pop-state-from-overlay current-state))) (mc/pop-state-from-overlay ,cs))))
(defun mc--compare-by-overlay-start (o1 o2) (defun mc--compare-by-overlay-start (o1 o2)
(< (overlay-start o1) (overlay-start o2))) (< (overlay-start o1) (overlay-start o2)))
(defmacro mc/for-each-cursor-ordered (&rest forms) (defmacro mc/for-each-cursor-ordered (&rest forms)
"Runs the body for each cursor, fake and real, bound to the name cursor" "Runs the body for each cursor, fake and real, bound to the name cursor"
`(let ((real-cursor-id (overlay-get (mc/create-fake-cursor-at-point) 'mc-id))) (let ((rci (make-symbol "real-cursor-id")))
`(let ((,rci (overlay-get (mc/create-fake-cursor-at-point) 'mc-id)))
(mapc #'(lambda (cursor) (mapc #'(lambda (cursor)
(when (mc/fake-cursor-p cursor) (when (mc/fake-cursor-p cursor)
,@forms)) ,@forms))
(sort (overlays-in (point-min) (point-max)) 'mc--compare-by-overlay-start)) (sort (overlays-in (point-min) (point-max)) 'mc--compare-by-overlay-start))
(mc/pop-state-from-overlay (mc/cursor-with-id real-cursor-id)))) (mc/pop-state-from-overlay (mc/cursor-with-id ,rci)))))
(defmacro mc/save-window-scroll (&rest forms) (defmacro mc/save-window-scroll (&rest forms)
"Saves and restores the window scroll position" "Saves and restores the window scroll position"
`(let ((p (set-marker (make-marker) (point))) (let ((p (make-symbol "p"))
(start (set-marker (make-marker) (window-start))) (s (make-symbol "start"))
(hscroll (window-hscroll))) (h (make-symbol "hscroll")))
`(let ((,p (set-marker (make-marker) (point)))
(,s (set-marker (make-marker) (window-start)))
(,h (window-hscroll)))
,@forms ,@forms
(goto-char p) (goto-char ,p)
(set-window-start nil start) (set-window-start nil ,s t)
(set-window-hscroll nil hscroll) (set-window-hscroll nil ,h)
(set-marker p nil) (set-marker ,p nil)
(set-marker start nil))) (set-marker ,s nil))))
(defun mc/make-cursor-overlay-at-eol (pos) (defun mc/make-cursor-overlay-at-eol (pos)
"Create overlay to look like cursor at end of line." "Create overlay to look like cursor at end of line."
@@ -118,22 +124,22 @@ highlights the entire width of the window."
(overlay-put overlay 'type 'additional-region) (overlay-put overlay 'type 'additional-region)
overlay)) overlay))
(defvar mc/cursor-specific-vars '(autopair-action (defvar mc/cursor-specific-vars '(transient-mark-mode
kill-ring
kill-ring-yank-pointer
mark-ring
mark-active
yank-undo-function
kill-ring-yank-pointer
autopair-action
autopair-wrap-action autopair-wrap-action
transient-mark-mode
er/history) er/history)
"A list of vars that need to be tracked on a per-cursor basis.") "A list of vars that need to be tracked on a per-cursor basis.")
(defun mc/store-current-state-in-overlay (o) (defun mc/store-current-state-in-overlay (o)
"Store relevant info about point and mark in the given overlay." "Store relevant info about point and mark in the given overlay."
(overlay-put o 'point (set-marker (make-marker) (point))) (overlay-put o 'point (set-marker (make-marker) (point)))
(overlay-put o 'kill-ring kill-ring)
(overlay-put o 'kill-ring-yank-pointer kill-ring-yank-pointer)
(overlay-put o 'mark (set-marker (make-marker) (mark))) (overlay-put o 'mark (set-marker (make-marker) (mark)))
(overlay-put o 'mark-ring mark-ring)
(overlay-put o 'mark-active mark-active)
(overlay-put o 'yank-undo-function yank-undo-function)
(overlay-put o 'kill-ring-yank-pointer kill-ring-yank-pointer)
(dolist (var mc/cursor-specific-vars) (dolist (var mc/cursor-specific-vars)
(when (boundp var) (overlay-put o var (symbol-value var)))) (when (boundp var) (overlay-put o var (symbol-value var))))
o) o)
@@ -141,13 +147,7 @@ highlights the entire width of the window."
(defun mc/restore-state-from-overlay (o) (defun mc/restore-state-from-overlay (o)
"Restore point and mark from stored info in the given overlay." "Restore point and mark from stored info in the given overlay."
(goto-char (overlay-get o 'point)) (goto-char (overlay-get o 'point))
(setq kill-ring (overlay-get o 'kill-ring))
(setq kill-ring-yank-pointer (overlay-get o 'kill-ring-yank-pointer))
(set-marker (mark-marker) (overlay-get o 'mark)) (set-marker (mark-marker) (overlay-get o 'mark))
(setq mark-ring (overlay-get o 'mark-ring))
(setq mark-active (overlay-get o 'mark-active))
(setq yank-undo-function (overlay-get o 'yank-undo-function))
(setq kill-ring-yank-pointer (overlay-get o 'kill-ring-yank-pointer))
(dolist (var mc/cursor-specific-vars) (dolist (var mc/cursor-specific-vars)
(when (boundp var) (set var (overlay-get o var))))) (when (boundp var) (set var (overlay-get o var)))))
@@ -223,6 +223,11 @@ cursor with updated info."
(mc/execute-command-for-fake-cursor cmd cursor))))) (mc/execute-command-for-fake-cursor cmd cursor)))))
(mc--reset-read-prompts)) (mc--reset-read-prompts))
(defun mc/execute-command-for-all-cursors (cmd)
"Calls CMD interactively for the real cursor and all fakes."
(call-interactively cmd)
(mc/execute-command-for-all-fake-cursors cmd))
;; Intercept some reading commands so you won't have to ;; Intercept some reading commands so you won't have to
;; answer them for every single cursor ;; answer them for every single cursor
@@ -301,8 +306,10 @@ been remapped. And certain modes (cua comes to mind) will change their
remapping based on state. So a command that changes the state will afterwards remapping based on state. So a command that changes the state will afterwards
not be recognized through the command-remapping lookup." not be recognized through the command-remapping lookup."
(unless mc--executing-command-for-fake-cursor (unless mc--executing-command-for-fake-cursor
(setq mc--this-command (or (command-remapping this-original-command) (let ((cmd (or (command-remapping this-original-command)
this-original-command)))) this-original-command)))
(setq mc--this-command (and (not (eq cmd 'god-mode-self-insert))
cmd)))))
(defun mc/execute-this-command-for-all-cursors () (defun mc/execute-this-command-for-all-cursors ()
"Wrap around `mc/execute-this-command-for-all-cursors-1' to protect hook." "Wrap around `mc/execute-this-command-for-all-cursors-1' to protect hook."
@@ -332,7 +339,6 @@ the original cursor, to inform about the lack of support."
(if (eq 1 (mc/num-cursors)) ;; no fake cursors? disable mc-mode (if (eq 1 (mc/num-cursors)) ;; no fake cursors? disable mc-mode
(multiple-cursors-mode 0) (multiple-cursors-mode 0)
(when this-original-command (when this-original-command
(let ((original-command (or mc--this-command (let ((original-command (or mc--this-command
(command-remapping this-original-command) (command-remapping this-original-command)
@@ -385,19 +391,22 @@ you should disable multiple-cursors-mode."
"Keymap while multiple cursors are active. "Keymap while multiple cursors are active.
Main goal of the keymap is to rebind C-g and <return> to conclude Main goal of the keymap is to rebind C-g and <return> to conclude
multiple cursors editing.") multiple cursors editing.")
(if mc/keymap (unless mc/keymap
nil
(setq mc/keymap (make-sparse-keymap)) (setq mc/keymap (make-sparse-keymap))
(define-key mc/keymap (kbd "C-g") 'mc/keyboard-quit) (define-key mc/keymap (kbd "C-g") 'mc/keyboard-quit)
(define-key mc/keymap (kbd "<return>") 'multiple-cursors-mode)) (define-key mc/keymap (kbd "<return>") 'multiple-cursors-mode)
(when (fboundp 'phi-search)
(define-key mc/keymap (kbd "C-s") 'phi-search))
(when (fboundp 'phi-search-backward)
(define-key mc/keymap (kbd "C-r") 'phi-search-backward)))
(defun mc--all-equal (entries) (defun mc--all-equal (list)
"Are all these entries equal?" "Are all the items in LIST equal?"
(let ((first (car entries)) (let ((first (car list))
(all-equal t)) (all-equal t))
(while (and all-equal entries) (while (and all-equal list)
(setq all-equal (equal first (car entries))) (setq all-equal (equal first (car list)))
(setq entries (cdr entries))) (setq list (cdr list)))
all-equal)) all-equal))
(defun mc--kill-ring-entries () (defun mc--kill-ring-entries ()
@@ -415,7 +424,7 @@ So you can paste it in later with `yank-rectangle'."
(unless (mc--all-equal entries) (unless (mc--all-equal entries)
(setq killed-rectangle entries)))) (setq killed-rectangle entries))))
(defvar mc/unsupported-minor-modes '(auto-complete-mode) (defvar mc/unsupported-minor-modes '(auto-complete-mode flyspell-mode)
"List of minor-modes that does not play well with multiple-cursors. "List of minor-modes that does not play well with multiple-cursors.
They are temporarily disabled when multiple-cursors are active.") They are temporarily disabled when multiple-cursors are active.")
@@ -564,12 +573,24 @@ for running commands with multiple cursors.")
mc/mark-all-words-like-this-in-defun mc/mark-all-words-like-this-in-defun
mc/mark-all-symbols-like-this-in-defun mc/mark-all-symbols-like-this-in-defun
mc/mark-all-like-this-dwim mc/mark-all-like-this-dwim
mc/mark-all-dwim
mc/mark-sgml-tag-pair mc/mark-sgml-tag-pair
mc/insert-numbers mc/insert-numbers
mc/sort-regions mc/sort-regions
mc/reverse-regions mc/reverse-regions
mc/cycle-forward mc/cycle-forward
mc/cycle-backward mc/cycle-backward
mc/add-cursor-on-click
mc/mark-pop
mc/add-cursors-to-all-matches
mc/mmlte--left
mc/mmlte--right
mc/mmlte--up
mc/mmlte--down
mc/unmark-next-like-this
mc/unmark-previous-like-this
mc/skip-to-next-like-this
mc/skip-to-previous-like-this
rrm/switch-to-multiple-cursors rrm/switch-to-multiple-cursors
save-buffer save-buffer
ido-exit-minibuffer ido-exit-minibuffer
@@ -655,6 +676,7 @@ for running commands with multiple cursors.")
backward-delete-char-untabify backward-delete-char-untabify
delete-char delete-forward-char delete-char delete-forward-char
delete-backward-char delete-backward-char
py-electric-backspace
c-electric-backspace c-electric-backspace
org-delete-backward-char org-delete-backward-char
paredit-backward-delete paredit-backward-delete
+1 -1
View File
@@ -1,2 +1,2 @@
(define-package "multiple-cursors" "1.2.0" (define-package "multiple-cursors" "1.3.0"
"Multiple cursors for Emacs.") "Multiple cursors for Emacs.")
+27 -9
View File
@@ -1,8 +1,9 @@
;;; multiple-cursors.el --- An experiment in multiple cursors for emacs. ;;; multiple-cursors.el --- Multiple cursors for emacs.
;; Copyright (C) 2012 Magnar Sveen ;; Copyright (C) 2012-2013 Magnar Sveen
;; Author: Magnar Sveen <magnars@gmail.com> ;; Author: Magnar Sveen <magnars@gmail.com>
;; Version: 1.2.2
;; Keywords: editing cursors ;; Keywords: editing cursors
;; This program is free software; you can redistribute it and/or modify ;; This program is free software; you can redistribute it and/or modify
@@ -66,6 +67,7 @@
;; - `mc/mark-previous-word-like-this`: Like `mc/mark-previous-like-this` but only for whole words. ;; - `mc/mark-previous-word-like-this`: Like `mc/mark-previous-like-this` but only for whole words.
;; - `mc/mark-previous-symbol-like-this`: Like `mc/mark-previous-like-this` but only for whole symbols. ;; - `mc/mark-previous-symbol-like-this`: Like `mc/mark-previous-like-this` but only for whole symbols.
;; - `mc/mark-more-like-this-extended`: Use arrow keys to quickly mark/skip next/previous occurances. ;; - `mc/mark-more-like-this-extended`: Use arrow keys to quickly mark/skip next/previous occurances.
;; - `mc/add-cursor-on-click`: Bind to a mouse event to add cursors by clicking. See tips-section.
;; ### Mark many occurrences ;; ### Mark many occurrences
@@ -91,27 +93,42 @@
;; - To get out of multiple-cursors-mode, press `<return>` or `C-g`. The latter will ;; - To get out of multiple-cursors-mode, press `<return>` or `C-g`. The latter will
;; first disable multiple regions before disabling multiple cursors. If you want to ;; first disable multiple regions before disabling multiple cursors. If you want to
;; insert a newline in multiple-cursors-mode, use `C-j`. ;; insert a newline in multiple-cursors-mode, use `C-j`.
;;
;; - Sometimes you end up with cursors outside of your view. You can ;; - Sometimes you end up with cursors outside of your view. You can
;; scroll the screen to center on each cursor with `C-v` and `M-v`. ;; scroll the screen to center on each cursor with `C-v` and `M-v`.
;;
;; - Try pressing `mc/mark-next-like-this` with no region selected. It will just add a cursor ;; - Try pressing `mc/mark-next-like-this` with no region selected. It will just add a cursor
;; on the next line. ;; on the next line.
;;
;; - Try pressing `mc/mark-all-like-this-dwim` on a tagname in html-mode. ;; - Try pressing `mc/mark-all-like-this-dwim` on a tagname in html-mode.
;;
;; - Notice that the number of cursors active can be seen in the modeline. ;; - Notice that the number of cursors active can be seen in the modeline.
;;
;; - If you get out of multiple-cursors-mode and yank - it will yank only ;; - If you get out of multiple-cursors-mode and yank - it will yank only
;; from the kill-ring of main cursor. To yank from the kill-rings of ;; from the kill-ring of main cursor. To yank from the kill-rings of
;; every cursor use yank-rectangle, normally found at C-x r y. ;; every cursor use yank-rectangle, normally found at C-x r y.
;;
;; - You can use `mc/reverse-regions` with nothing selected and just one cursor.
;; It will then flip the sexp at point and the one below it.
;;
;; - If you would like to keep the global bindings clean, and get custom keybindings ;; - If you would like to keep the global bindings clean, and get custom keybindings
;; when the region is active, you can try [region-bindings-mode](https://github.com/fgallina/region-bindings-mode). ;; when the region is active, you can try [region-bindings-mode](https://github.com/fgallina/region-bindings-mode).
;;
;; BTW, I highly recommend adding `mc/mark-next-like-this` to a key binding that's ;; BTW, I highly recommend adding `mc/mark-next-like-this` to a key binding that's
;; right next to the key for `er/expand-region`. ;; right next to the key for `er/expand-region`.
;; ### Binding mouse events
;; To override a mouse event, you will likely have to also unbind the
;; `down-mouse` part of the event. Like this:
;;
;; (global-unset-key (kbd "M-<down-mouse-1>"))
;; (global-set-key (kbd "M-<mouse-1>") 'mc/add-cursor-on-click)
;;
;; Or you can do like me and find an unused, but less convenient, binding:
;;
;; (global-set-key (kbd "C-S-<mouse-1>") 'mc/add-cursor-on-click)
;; ## Unknown commands ;; ## Unknown commands
;; Multiple-cursors uses two lists of commands to know what to do: the run-once list ;; Multiple-cursors uses two lists of commands to know what to do: the run-once list
@@ -165,6 +182,7 @@
(require 'mc-edit-lines) (require 'mc-edit-lines)
(require 'mc-cycle-cursors) (require 'mc-cycle-cursors)
(require 'mc-mark-more) (require 'mc-mark-more)
(require 'mc-mark-pop)
(require 'rectangular-region-mode) (require 'rectangular-region-mode)
(require 'mc-separate-operations) (require 'mc-separate-operations)
+4 -1
View File
@@ -67,6 +67,9 @@ an exceedingly quick way of adding multiple cursors to multiple lines."
(defun rrm/repaint () (defun rrm/repaint ()
"Start from the anchor and draw a rectangle between it and point." "Start from the anchor and draw a rectangle between it and point."
(if (not rectangular-region-mode)
(remove-hook 'post-command-hook 'rrm/repaint t)
;; else
(rrm/remove-rectangular-region-overlays) (rrm/remove-rectangular-region-overlays)
(let* ((annoying-arrows-mode nil) (let* ((annoying-arrows-mode nil)
(point-column (current-column)) (point-column (current-column))
@@ -87,7 +90,7 @@ an exceedingly quick way of adding multiple cursors to multiple lines."
(set-mark (point)) (set-mark (point))
(move-to-column point-column) (move-to-column point-column)
(when (= point-column (current-column)) (when (= point-column (current-column))
(mc/create-fake-cursor-at-point))))))) (mc/create-fake-cursor-at-point))))))))
(defun rrm/switch-to-multiple-cursors (&rest forms) (defun rrm/switch-to-multiple-cursors (&rest forms)
"Switch from rectangular-region-mode to multiple-cursors-mode." "Switch from rectangular-region-mode to multiple-cursors-mode."
Executable
+2
View File
@@ -0,0 +1,2 @@
#!/bin/sh -e
cask exec ecukes "$@" --no-win
+3 -2
View File
@@ -2,11 +2,12 @@
cd "$(dirname "$0")" cd "$(dirname "$0")"
ECUKES_EMACS=${ECUKES_EMACS:-$(which emacs)} ECUKES_EMACS=${EMACS:-$(which emacs)}
export ECUKES_EMACS
echo "*** Emacs version ***" echo "*** Emacs version ***"
echo "ECUKES_EMACS = $ECUKES_EMACS" echo "ECUKES_EMACS = $ECUKES_EMACS"
"$ECUKES_EMACS" --version "$ECUKES_EMACS" --version
echo echo
exec ./util/ecukes/ecukes --graphical exec ./run-tests.sh $TAGS
Submodule util/ecukes deleted from b2c449cf01
-2544
View File
File diff suppressed because it is too large Load Diff
Submodule util/espuds deleted from 62ef75cb51
-329
View File
@@ -1,329 +0,0 @@
;;; wrap-region.el --- Wrap text with punctation or tag
;; Copyright (C) 2008-2012 Johan Andersson
;; Author: Johan Andersson <johan.rejeep@gmail.com>
;; Maintainer: Johan Andersson <johan.rejeep@gmail.com>
;; Version: 0.6.0
;; Keywords: speed, convenience
;; URL: http://github.com/rejeep/wrap-region
;; This file is NOT part of GNU Emacs.
;;; License:
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to the
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;; wrap-region is a minor mode that wraps a region with
;; punctuations. For tagged markup modes, such as HTML and XML, it
;; wraps with tags.
;;
;; To use wrap-region, make sure that this file is in Emacs load-path:
;; (add-to-list 'load-path "/path/to/directory/or/file")
;;
;; Then require wrap-region:
;; (require 'wrap-region)
;; To start wrap-region:
;; (wrap-region-mode t) or M-x wrap-region-mode
;;
;; If you only want wrap-region active in some mode, use hooks:
;; (add-hook 'ruby-mode-hook 'wrap-region-mode)
;;
;; Or if you want to activate it in all buffers, use the global mode:
;; (wrap-region-global-mode t)
;; To wrap a region, select that region and hit one of the punctuation
;; keys. In "tag-modes"" (see `wrap-region-tag-active-modes'), "<" is
;; replaced and wraps the region with a tag. To activate this behavior
;; in a mode that is not default:
;; (add-to-list 'wrap-region-tag-active-modes 'some-tag-mode)
;;
;; `wrap-region-table' contains the default punctuations
;; that wraps. You can add and remove new wrappers by using the
;; functions `wrap-region-add-wrapper' and
;; `wrap-region-remove-wrapper' respectively.
;; (wrap-region-add-wrapper "`" "'") ; hit ` then region -> `region'
;; (wrap-region-add-wrapper "/*" "*/" "/") ; hit / then region -> /*region*/
;; (wrap-region-add-wrapper "$" "$" nil 'latex-mode) ; hit $ then region -> $region$ in latex-mode
;; (wrap-region-remove-wrapper "(")
;; (wrap-region-remove-wrapper "$" 'latex-mode)
;;
;; Some modes may have conflicting key bindings with wrap-region. To
;; avoid conflicts, the list `wrap-region-except-modes' contains names
;; of modes where wrap-region should not be activated (note, only in
;; the global mode). You can add new modes like this:
;; (add-to-list 'wrap-region-except-modes 'conflicting-mode)
;;; Code:
(require 'edmacro)
(eval-when-compile
(require 'cl))
(defstruct wrap-region-wrapper key left right modes)
(defvar wrap-region-mode-map (make-sparse-keymap)
"Keymap for `wrap-region-mode'.")
(defvar wrap-region-table (make-hash-table :test 'equal)
"Table with wrapper pairs.")
(defvar wrap-region-tag-active-modes '(html-mode sgml-mode rhtml-mode nxml-mode nxhtml-mode)
"List of modes that uses tags.")
(defvar wrap-region-except-modes '(calc-mode dired-mode)
"A list of modes in which `wrap-region-mode' should not be activated.")
(defvar wrap-region-hook nil
"Called when `wrap-region-mode' is turned on.")
(defvar wrap-region-before-wrap-hook nil
"Called before wrapping.")
(defvar wrap-region-after-wrap-hook nil
"Called after wrapping.")
(defvar wrap-region-only-with-negative-prefix nil
"Only wrap if the trigger key is prefixed with a negative value.")
(defvar wrap-region-keep-mark nil
"Keep the wrapped region active.")
(defun wrap-region-trigger (arg key)
"Called when trigger key is pressed."
(let* ((wrapper (wrap-region-find key)))
(if (and wrapper
(region-active-p)
(if wrap-region-only-with-negative-prefix (< arg 0) t))
(if (wrap-region-insert-tag-p key)
(wrap-region-with-tag)
(wrap-region-with-punctuations
(wrap-region-wrapper-left wrapper)
(wrap-region-wrapper-right wrapper)))
(wrap-region-fallback key))))
(defun wrap-region-find (key)
"Find first wrapper with trigger KEY that should be active in MAJOR-MODE."
(let ((wrappers (gethash key wrap-region-table)))
(or
(find-if
(lambda (wrapper)
(member major-mode (wrap-region-wrapper-modes wrapper)))
wrappers)
(find-if
(lambda (wrapper)
(not (wrap-region-wrapper-modes wrapper)))
wrappers))))
(defun wrap-region-insert-tag-p (key)
"Check if tag should be inserted or not."
(and
(equal key "<")
(member major-mode wrap-region-tag-active-modes)))
(defun wrap-region-with-tag ()
"Wraps region with tag."
(let* ((tag (read-string "Enter Tag (with optional attributes): "))
(split (split-string tag " "))
(tag-name (car split))
(left (concat "<" tag ">"))
(right (concat "</" tag-name ">")))
(wrap-region-with left right)))
(defun wrap-region-with-punctuations (left right)
"Wraps region with LEFT and RIGHT punctuations."
(wrap-region-with left right))
(defun wrap-region-with (left right)
"Wraps region with LEFT and RIGHT."
(run-hooks 'wrap-region-before-wrap-hook)
(let ((beg (region-beginning))
(end (region-end))
(pos (point))
(deactivate-mark nil))
(save-excursion
(goto-char beg)
(insert left)
(goto-char (+ end (length left)))
(insert right))
(if wrap-region-keep-mark
(let* ((beg-p (eq beg pos))
(beg* (+ beg (length left)))
(end* (+ end (length left)))
(pos* (if beg-p beg* end*)))
(push-mark (if beg-p end* beg*) nil t)
(goto-char (if beg-p beg* end*)))
(deactivate-mark)))
(run-hooks 'wrap-region-after-wrap-hook))
(defun wrap-region-fallback (key)
"Execute function that KEY was bound to before `wrap-region-mode'."
(let ((wrap-region-mode nil))
(execute-kbd-macro
(edmacro-parse-keys key))))
(defun wrap-region-add-wrappers (wrappers)
"Add WRAPPERS by calling `wrap-region-add-wrapper' for each one."
(mapc
(lambda (wrapper)
(apply 'wrap-region-add-wrapper wrapper))
wrappers))
(defun wrap-region-add-wrapper (left right &optional key mode-or-modes)
"Add new LEFT and RIGHT wrapper.
Optional KEY is the trigger key and MODE-OR-MODES is a single
mode or multiple modes that the wrapper should trigger in."
(or key (setq key left))
(let ((wrappers (gethash key wrap-region-table))
(modes
(if mode-or-modes
(if (listp mode-or-modes)
mode-or-modes
(list mode-or-modes)))))
(if wrappers
(let ((wrapper-exactly-same
(find-if
(lambda (wrapper)
(and
(equal (wrap-region-wrapper-key wrapper) key)
(equal (wrap-region-wrapper-left wrapper) left)
(equal (wrap-region-wrapper-right wrapper) right)))
wrappers)))
(if wrapper-exactly-same
(when (wrap-region-wrapper-modes wrapper-exactly-same)
(if modes
(setf
(wrap-region-wrapper-modes wrapper-exactly-same)
(union modes (wrap-region-wrapper-modes wrapper-exactly-same)))
(let ((new-wrapper (make-wrap-region-wrapper :key key :left left :right right)))
(puthash key (cons new-wrapper wrappers) wrap-region-table))))
(let* ((new-wrapper (make-wrap-region-wrapper :key key :left left :right right :modes modes))
(wrapper-same-trigger
(find-if
(lambda (wrapper)
(equal (wrap-region-wrapper-key wrapper) key))
wrappers))
(wrapper-same-trigger-modes
(wrap-region-wrapper-modes wrapper-same-trigger)))
(when (and wrapper-same-trigger wrapper-same-trigger-modes)
(let ((new-modes (nset-difference (wrap-region-wrapper-modes wrapper-same-trigger) modes)))
(if new-modes
(setf (wrap-region-wrapper-modes wrapper-same-trigger) new-modes)
(setq wrappers (delete wrapper-same-trigger wrappers)))))
(puthash key (cons new-wrapper wrappers) wrap-region-table))))
(let ((new-wrapper (make-wrap-region-wrapper :key key :left left :right right :modes modes)))
(puthash key (list new-wrapper) wrap-region-table))))
(wrap-region-define-trigger key))
(defun wrap-region-remove-wrapper (key &optional mode-or-modes)
"Remove wrapper with trigger KEY or exclude from MODE-OR-MODES.
If MODE-OR-MODES is not present, all wrappers for KEY are removed."
(if mode-or-modes
(let ((wrappers (gethash key wrap-region-table))
(modes
(if mode-or-modes
(if (listp mode-or-modes)
mode-or-modes
(list mode-or-modes)))))
(mapc
(lambda (mode)
(let ((wrapper-including-mode
(find-if
(lambda (wrapper)
(member mode (wrap-region-wrapper-modes wrapper)))
wrappers)))
(when wrapper-including-mode
(let ((new-modes (delete mode (wrap-region-wrapper-modes wrapper-including-mode))))
(if new-modes
(setf (wrap-region-wrapper-modes wrapper-including-mode) new-modes)
(puthash key (delete wrapper-including-mode wrappers) wrap-region-table))))))
modes))
(wrap-region-destroy-wrapper key)))
(defun wrap-region-destroy-wrapper (key)
"Remove the wrapper bound to KEY, no questions asked."
(remhash key wrap-region-table)
(wrap-region-unset-key key))
(defun wrap-region-define-wrappers ()
"Defines defaults wrappers."
(mapc
(lambda (pair)
(apply 'wrap-region-add-wrapper pair))
'(("\"" "\"")
("'" "'")
("(" ")")
("{" "}")
("[" "]")
("<" ">"))))
(defun wrap-region-define-trigger (key)
"Defines KEY as wrapper."
(wrap-region-define-key
key
`(lambda (arg)
(interactive "p")
(wrap-region-trigger arg ,key))))
(defun wrap-region-unset-key (key)
"Remove KEY from `wrap-region-mode-map'."
(wrap-region-define-key key))
(defun wrap-region-define-key (key &optional fn)
"Binds KEY to FN in `wrap-region-mode-map'."
(define-key wrap-region-mode-map (read-kbd-macro key) fn))
;;;###autoload
(define-minor-mode wrap-region-mode
"Wrap region with stuff."
:init-value nil
:lighter " wr"
:keymap wrap-region-mode-map
(when wrap-region-mode
(wrap-region-define-wrappers)
(run-hooks 'wrap-region-hook)))
;;;###autoload
(defun turn-on-wrap-region-mode ()
"Turn on `wrap-region-mode'"
(interactive)
(unless (member major-mode wrap-region-except-modes)
(wrap-region-mode +1)))
;;;###autoload
(defun turn-off-wrap-region-mode ()
"Turn off `wrap-region-mode'."
(interactive)
(wrap-region-mode -1))
;;;###autoload
(define-globalized-minor-mode wrap-region-global-mode
wrap-region-mode
turn-on-wrap-region-mode)
(provide 'wrap-region)
;;; wrap-region.el ends here
+2 -2
View File
@@ -7,13 +7,13 @@ end
def run_all_tests def run_all_tests
system('clear') system('clear')
result = run "./util/ecukes/ecukes --graphical" result = run "./run-tests.sh"
puts result puts result
end end
def run_test(file) def run_test(file)
system('clear') system('clear')
result = run "./util/ecukes/ecukes --graphical #{file}" result = run "./run-tests.sh #{file} --verbose"
puts result puts result
end end