mirror of
https://github.com/magnars/multiple-cursors.el.git
synced 2026-05-10 09:28:18 +00:00
Compare commits
221 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 340ff672a5 | |||
| 6a7c3c0853 | |||
| 8172edd05a | |||
| 3f382d2c8f | |||
| 9c49874fa4 | |||
| 038815b2b9 | |||
| 75dd6bf83a | |||
| 35ff8b5ef1 | |||
| e419903612 | |||
| 0e49fecc18 | |||
| eba10208fc | |||
| f628df72a1 | |||
| 1075270008 | |||
| e048e04bd8 | |||
| 6f183a1e82 | |||
| f33cdd4935 | |||
| 18f992bff5 | |||
| f6bac949a0 | |||
| e14fdb77a1 | |||
| d2766bc215 | |||
| c94566597a | |||
| 7cb18b8aec | |||
| fa91dfb9bd | |||
| ddbe3ae932 | |||
| 616fd84891 | |||
| 632768113d | |||
| 277aef4f0b | |||
| dfaf6215fc | |||
| 95f2e41fab | |||
| 8e59a8a226 | |||
| 6d8c6fcc83 | |||
| 67d6579eab | |||
| 21e48250ec | |||
| ad95d287c7 | |||
| 60b9ef8347 | |||
| d9a6047d1a | |||
| 8413969a97 | |||
| 2ccfc74bf4 | |||
| d26cecd53a | |||
| 2329611a41 | |||
| fd847ae6e7 | |||
| be149f9121 | |||
| 3112e61824 | |||
| a508978cd9 | |||
| a9daac129a | |||
| 741eec6766 | |||
| be4fbc702e | |||
| b3bd49c756 | |||
| fb0e71a62a | |||
| 432a3fc8d6 | |||
| 1686630fd6 | |||
| 9f4cdd0907 | |||
| 6a62e60bf2 | |||
| da069c88e5 | |||
| d5b544ef9c | |||
| 4bf9860bcc | |||
| 8297f1f210 | |||
| 06a2985db0 | |||
| 8ac4ad3e28 | |||
| e31b1eb59c | |||
| e17851efd3 | |||
| 4c52fb1e56 | |||
| 40eb74e3e4 | |||
| 54c05c3e24 | |||
| 68961b4cf3 | |||
| 55af65920b | |||
| a393384b35 | |||
| 415e29f1d1 | |||
| dd07bc50ea | |||
| 8703b19872 | |||
| bbbe90d274 | |||
| 36b7025a35 | |||
| ca822cd0d0 | |||
| 97e5db17c5 | |||
| 3f1611c7cb | |||
| 9b53e892e6 | |||
| cd967e720f | |||
| 2e904a0be2 | |||
| 5d677f765c | |||
| 49c9f7f6bf | |||
| c90bb624db | |||
| 2588ccef69 | |||
| 142fdd6534 | |||
| 66b1127489 | |||
| 533e1576e3 | |||
| faf331dfae | |||
| 89e360e96c | |||
| 97f7b1d598 | |||
| 4969d382de | |||
| 2d6ffce4c9 | |||
| 72b4bf3911 | |||
| cec48cc78f | |||
| 7d843984b3 | |||
| 7cf6374333 | |||
| dc1bfbf816 | |||
| 952877fc5b | |||
| f0dcd06c6f | |||
| ff0ac1fc75 | |||
| 82586a0f66 | |||
| adf86bd4c8 | |||
| 40b1bad8ac | |||
| 19f842d60a | |||
| 66eefa2963 | |||
| 49fe803f3b | |||
| 912342ed85 | |||
| b46f79566e | |||
| 715665129e | |||
| 7ddda8527b | |||
| f3daf86bd6 | |||
| 4b0e91239e | |||
| bf9e8e95e0 | |||
| 653d52352d | |||
| 38d6013d18 | |||
| b3fd49c1d9 | |||
| 98f2346f03 | |||
| 9f4502b7bc | |||
| e94567c8e6 | |||
| 4da58ea6dd | |||
| d184f353ef | |||
| 084714791b | |||
| fc39dab1cb | |||
| da2a9abfd8 | |||
| a3e6ec7c93 | |||
| d1ad51f1a6 | |||
| 7b4dd88a69 | |||
| f5866d62d9 | |||
| 5cd6ddf788 | |||
| 38e590ce06 | |||
| 238fb970f9 | |||
| 3cfae1dac2 | |||
| 00aea4c9d7 | |||
| 75ece6884b | |||
| aed5d592cf | |||
| 5fead7d83e | |||
| 2682e48204 | |||
| 2d639b0f45 | |||
| 2b536cb8b6 | |||
| c69be0e672 | |||
| 239acbfbc8 | |||
| cfe4bd9eb3 | |||
| 54e408fc68 | |||
| 17c48f972a | |||
| 6467fe251d | |||
| d17c89e418 | |||
| 65c0c0c6fe | |||
| ec4781394c | |||
| ad79ad8b52 | |||
| 18d858f0de | |||
| 68dfa461f1 | |||
| a86daa79ce | |||
| 8dfe725c4f | |||
| d8c5227443 | |||
| 9f91a0455d | |||
| bf4b0c669b | |||
| 45ed43e1f8 | |||
| af66635a05 | |||
| 61388fedef | |||
| 49027c6717 | |||
| 5e879f9b5c | |||
| 23459589eb | |||
| e28090d635 | |||
| be7905d9e0 | |||
| a37403178f | |||
| 45c6cd0be4 | |||
| 186cb3b63f | |||
| c94eca57ae | |||
| 725369c445 | |||
| e8d734452e | |||
| 398cc9e466 | |||
| 6745142d87 | |||
| 47e03d54f4 | |||
| 39f17258b8 | |||
| 2186e1b6e5 | |||
| 66ceb0b0d4 | |||
| 6cff0c2ebd | |||
| 4c293c46fd | |||
| 754de4e63b | |||
| 1cb894d119 | |||
| cc45842384 | |||
| 94af07453d | |||
| cb848b2a39 | |||
| 474838666a | |||
| 53db250b43 | |||
| 75df47fc4a | |||
| 4535033952 | |||
| 69c99618f9 | |||
| 7a236d174e | |||
| 374244b66e | |||
| 8b91e4788c | |||
| bf0177205e | |||
| 6e159238b2 | |||
| 9dac934bce | |||
| ccb42b5d70 | |||
| 8a53db8a39 | |||
| 72ba43a08e | |||
| 16589a5af2 | |||
| 980a8808dd | |||
| ed18fa49c1 | |||
| 1cdd73037f | |||
| aa9a1ece7b | |||
| 25dd14d350 | |||
| 373dcbe002 | |||
| d24ddc53ea | |||
| 5c60757080 | |||
| a6e0ccb22f | |||
| 0ee76bfad1 | |||
| e7a5fe61c4 | |||
| 641eb680ca | |||
| 16add89d29 | |||
| cb7a145153 | |||
| 82a1fe3746 | |||
| 56839dfdca | |||
| 3f3cdc6c92 | |||
| 5190e0cdc6 | |||
| a4f6ea179a | |||
| 9582c7220b | |||
| a6984a1141 | |||
| 6a5969e14a | |||
| 9a376a6fa2 | |||
| bfb293f200 | |||
| 3ce6e4a670 |
@@ -0,0 +1,3 @@
|
|||||||
|
elpa
|
||||||
|
*.elc
|
||||||
|
/.ecukes-failing-scenarios
|
||||||
@@ -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
|
|
||||||
+5
-4
@@ -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/cask/cask/master/go | python
|
||||||
|
- 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
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
(source gnu)
|
||||||
|
(source melpa)
|
||||||
|
|
||||||
|
(package-file "multiple-cursors.el")
|
||||||
|
|
||||||
|
(development
|
||||||
|
(depends-on "ecukes")
|
||||||
|
(depends-on "espuds")
|
||||||
|
(depends-on "wrap-region"))
|
||||||
@@ -4,6 +4,18 @@ Multiple cursors for Emacs. This is some pretty crazy functionality, so yes,
|
|||||||
there are kinks. Don't be afraid tho, I've been using it since 2011 with
|
there are kinks. Don't be afraid tho, I've been using it since 2011 with
|
||||||
great success and much merriment.
|
great success and much merriment.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
I highly recommend installing multiple-cursors through `package.el`.
|
||||||
|
|
||||||
|
It's available on [MELPA](http://melpa.org/) and [MELPA Stable](http://stable.melpa.org):
|
||||||
|
|
||||||
|
M-x package-install multiple-cursors
|
||||||
|
|
||||||
|
The package depends on the `cl-lib` package, so if you do not use
|
||||||
|
`package.el` or have a recent Emacs, you would need to install that
|
||||||
|
too: see [GNU ELPA](http://elpa.gnu.org/packages/cl-lib.html).
|
||||||
|
|
||||||
## Basic usage
|
## Basic usage
|
||||||
|
|
||||||
Start out with:
|
Start out with:
|
||||||
@@ -31,6 +43,10 @@ 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`.
|
||||||
|
|
||||||
|
## Important note
|
||||||
|
|
||||||
|
Multiple cursors does not do well when you invoke its commands with `M-x`. It needs to be bound to keys to work properly. Pull request to fix this is welcome.
|
||||||
|
|
||||||
## Video
|
## Video
|
||||||
|
|
||||||
You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.com/e13.html).
|
You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.com/e13.html).
|
||||||
@@ -40,15 +56,31 @@ You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.co
|
|||||||
### Mark one more occurrence
|
### Mark one more occurrence
|
||||||
|
|
||||||
- `mc/mark-next-like-this`: Adds a cursor and region at the next part of the buffer forwards that matches the current region.
|
- `mc/mark-next-like-this`: Adds a cursor and region at the next part of the buffer forwards that matches the current region.
|
||||||
|
- `mc/mark-next-like-this-word`: Adds a cursor and region at the next part of the buffer forwards that matches the current region, if no region is selected it selects the word at the point.
|
||||||
|
- `mc/mark-next-like-this-symbol`: Adds a cursor and region at the next part of the buffer forwards that matches the current region, if no region is selected it selects the symbol at the point.
|
||||||
- `mc/mark-next-word-like-this`: Like `mc/mark-next-like-this` but only for whole words.
|
- `mc/mark-next-word-like-this`: Like `mc/mark-next-like-this` but only for whole words.
|
||||||
- `mc/mark-next-symbol-like-this`: Like `mc/mark-next-like-this` but only for whole symbols.
|
- `mc/mark-next-symbol-like-this`: Like `mc/mark-next-like-this` but only for whole symbols.
|
||||||
- `mc/mark-previous-like-this`: Adds a cursor and region at the next part of the buffer backwards that matches the current region.
|
- `mc/mark-previous-like-this`: Adds a cursor and region at the next part of the buffer backwards that matches the current region.
|
||||||
|
- `mc/mark-previous-like-this-word`: Adds a cursor and region at the next part of the buffer backwards that matches the current region, if no region is selected it selects the word at the point.
|
||||||
|
- `mc/mark-previous-like-this-symbol`: Adds a cursor and region at the next part of the buffer backwards that matches the current region, if no region is selected it selects the symbol at the point.
|
||||||
- `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/mark-pop`: 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.
|
||||||
|
|
||||||
### Mark many occurrences
|
### Mark many occurrences
|
||||||
|
|
||||||
|
- `mc/edit-lines`: Adds one cursor to each line in the current region.
|
||||||
|
- `mc/edit-beginnings-of-lines`: Adds a cursor at the start of each line in the current region.
|
||||||
|
- `mc/edit-ends-of-lines`: Adds a cursor at the end of each line in the current region.
|
||||||
- `mc/mark-all-like-this`: Marks all parts of the buffer that matches the current region.
|
- `mc/mark-all-like-this`: Marks all parts of the buffer that matches the current region.
|
||||||
- `mc/mark-all-words-like-this`: Like `mc/mark-all-like-this` but only for whole words.
|
- `mc/mark-all-words-like-this`: Like `mc/mark-all-like-this` but only for whole words.
|
||||||
- `mc/mark-all-symbols-like-this`: Like `mc/mark-all-like-this` but only for whole symbols.
|
- `mc/mark-all-symbols-like-this`: Like `mc/mark-all-like-this` but only for whole symbols.
|
||||||
@@ -56,12 +88,16 @@ 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
|
||||||
|
|
||||||
- `set-rectangular-region-anchor`: Think of this one as `set-mark` except you're marking a rectangular region.
|
- `set-rectangular-region-anchor`: Think of this one as `set-mark` except you're marking a rectangular region.
|
||||||
- `mc/mark-sgml-tag-pair`: Mark the current opening and closing tag.
|
- `mc/mark-sgml-tag-pair`: Mark the current opening and closing tag.
|
||||||
|
- `mc/insert-numbers`: Insert increasing numbers for each cursor, top to bottom.
|
||||||
|
- `mc/insert-letters`: Insert increasing letters for each cursor, top to bottom.
|
||||||
|
- `mc/sort-regions`: Sort the marked regions alphabetically.
|
||||||
|
- `mc/reverse-regions`: Reverse the order of the marked regions.
|
||||||
|
|
||||||
## Tips and tricks
|
## Tips and tricks
|
||||||
|
|
||||||
@@ -69,22 +105,52 @@ You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.co
|
|||||||
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
|
- `(define-key mc/keymap (kbd "<return>") nil)` will make `<return>` insert a
|
||||||
scroll the screen to center on each cursor with `C-v` and `M-v`.
|
newline; multiple-cursors-mode can still be disabled with `C-g`.
|
||||||
|
|
||||||
- Try pressing `mc/mark-next-like-this` with no region selected. It will just add a cursor
|
- Sometimes you end up with cursors outside of your view. You can
|
||||||
on the next line.
|
scroll the screen to center on each cursor with `C-v` and `M-v` or you can
|
||||||
|
press `C-'` to hide all lines without a cursor, press `C-'` again to unhide.
|
||||||
|
|
||||||
|
- Try pressing `mc/mark-next-like-this` with no region selected. It
|
||||||
|
will just add a cursor on the next line.
|
||||||
|
|
||||||
|
- Try pressing `mc/mark-next-like-this-word` or
|
||||||
|
`mc/mark-next-like-this-symbol` with no region selected. It will
|
||||||
|
mark the word or symbol and add a cursor at the next occurance
|
||||||
|
|
||||||
- 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
|
||||||
|
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.
|
||||||
|
|
||||||
|
- 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.
|
||||||
|
|
||||||
|
- When you use `mc/edit-lines`, you can give it a positive or negative
|
||||||
|
prefix to change how it behaves on too short lines.
|
||||||
|
|
||||||
- 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
|
||||||
@@ -97,11 +163,17 @@ the location with:
|
|||||||
|
|
||||||
(setq mc/list-file "/my/preferred/file")
|
(setq mc/list-file "/my/preferred/file")
|
||||||
|
|
||||||
|
NB! Make sure to do so before requiring multiple-cursors.
|
||||||
|
|
||||||
|
It is possible to set multiple-cursors to "run-for-all" for every
|
||||||
|
command except for those that are listed in `mc/cmds-to-run-once`. To
|
||||||
|
enable this set `mc/always-run-for-all` to non-nil. Add commands to be
|
||||||
|
run once to `mc/cmds-to-run-once` in ".mc-lists.el".
|
||||||
|
|
||||||
## 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.
|
||||||
@@ -117,27 +189,35 @@ 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, and different options for how to handle short lines in `mc/edit-lines`.
|
||||||
* [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`
|
||||||
|
* [Aleksey Fedotov](https://github.com/lexa) added `mc-hide-unmatched-lines-mode`
|
||||||
|
* [Jules Tamagnan](https://github.com/jtamagnan) added `mc/mark-next-like-this-word` and `mc/mark-next-like-this-symbol`
|
||||||
|
* [Ingo Lohmar](https://github.com/ilohmar) extended `mc/add-cursor-on-click` to toggle cursors.
|
||||||
|
* [Andrea Orru](https://github.com/AndreaOrru) added `mc/mark-previous-like-this-word`/`-symbol`
|
||||||
|
|
||||||
Thanks!
|
Thanks!
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
Copyright (C) 2012 Magnar Sveen
|
Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
Author: Magnar Sveen <magnars@gmail.com>
|
Author: Magnar Sveen <magnars@gmail.com>
|
||||||
Keywords: editing cursors
|
Keywords: editing cursors
|
||||||
|
|||||||
@@ -42,3 +42,99 @@ Feature: Switching from a multiline region to multiple cursors
|
|||||||
And I go to the front of the word "long"
|
And I go to the front of the word "long"
|
||||||
And I press "C-S-c C-S-c"
|
And I press "C-S-c C-S-c"
|
||||||
Then I should have 2 cursors
|
Then I should have 2 cursors
|
||||||
|
|
||||||
|
Scenario: Edit without using transient mark mode
|
||||||
|
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 "C-S-c C-S-c"
|
||||||
|
Then I should have 2 cursors
|
||||||
|
|
||||||
|
Scenario: Edit default short lines
|
||||||
|
When I insert:
|
||||||
|
"""
|
||||||
|
hello
|
||||||
|
|
||||||
|
there
|
||||||
|
"""
|
||||||
|
And I go to the end of the word "hello"
|
||||||
|
And I set the mark
|
||||||
|
And I go to the end of the word "there"
|
||||||
|
And I press "C-S-c C-S-c"
|
||||||
|
And I press "you"
|
||||||
|
Then I should see:
|
||||||
|
"""
|
||||||
|
helloyou
|
||||||
|
you
|
||||||
|
thereyou
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Pad short lines
|
||||||
|
When I insert:
|
||||||
|
"""
|
||||||
|
hello
|
||||||
|
|
||||||
|
there
|
||||||
|
"""
|
||||||
|
And I go to the end of the word "hello"
|
||||||
|
And I set the mark
|
||||||
|
And I go to the end of the word "there"
|
||||||
|
And I press "M-1 C-S-c C-S-c"
|
||||||
|
Then I should have 3 cursors
|
||||||
|
|
||||||
|
Scenario: Edit padding short lines
|
||||||
|
When I insert:
|
||||||
|
"""
|
||||||
|
hello
|
||||||
|
|
||||||
|
there
|
||||||
|
"""
|
||||||
|
And I go to the end of the word "hello"
|
||||||
|
And I set the mark
|
||||||
|
And I go to the end of the word "there"
|
||||||
|
And I press "M-1 C-S-c C-S-c"
|
||||||
|
And I press "you"
|
||||||
|
Then I should see:
|
||||||
|
"""
|
||||||
|
helloyou
|
||||||
|
you
|
||||||
|
thereyou
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Skip short lines
|
||||||
|
When I insert:
|
||||||
|
"""
|
||||||
|
hello
|
||||||
|
|
||||||
|
there
|
||||||
|
"""
|
||||||
|
And I go to the end of the word "hello"
|
||||||
|
And I set the mark
|
||||||
|
And I go to the end of the word "there"
|
||||||
|
And I press "M-- M-1 C-S-c C-S-c"
|
||||||
|
Then I should have 2 cursors
|
||||||
|
|
||||||
|
Scenario: Edit skipping short lines
|
||||||
|
When I insert:
|
||||||
|
"""
|
||||||
|
hello
|
||||||
|
|
||||||
|
there
|
||||||
|
"""
|
||||||
|
And I go to the end of the word "hello"
|
||||||
|
And I set the mark
|
||||||
|
And I go to the end of the word "there"
|
||||||
|
And I press "M-- M-1 C-S-c C-S-c"
|
||||||
|
And I press "you"
|
||||||
|
Then I should see:
|
||||||
|
"""
|
||||||
|
helloyou
|
||||||
|
|
||||||
|
thereyou
|
||||||
|
"""
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
Feature: Hiding lines without cursor
|
||||||
|
|
||||||
|
Scenario: Hiding lines when three cursor active
|
||||||
|
Given I have cursors at "line" in :
|
||||||
|
"""
|
||||||
|
0
|
||||||
|
line
|
||||||
|
2
|
||||||
|
3
|
||||||
|
line
|
||||||
|
5
|
||||||
|
6
|
||||||
|
7
|
||||||
|
8
|
||||||
|
9
|
||||||
|
10
|
||||||
|
11
|
||||||
|
line
|
||||||
|
13
|
||||||
|
14
|
||||||
|
15
|
||||||
|
"""
|
||||||
|
And I press "C-'"
|
||||||
|
Then I should have 3 cursors
|
||||||
|
Then I should see exactly:
|
||||||
|
"""
|
||||||
|
0
|
||||||
|
line
|
||||||
|
2
|
||||||
|
3
|
||||||
|
line
|
||||||
|
5
|
||||||
|
6
|
||||||
|
|
||||||
|
10
|
||||||
|
11
|
||||||
|
line
|
||||||
|
13
|
||||||
|
14
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
Scenario: Hiding lines when only two cursor active
|
||||||
|
When I insert:
|
||||||
|
"""
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
text
|
||||||
|
6
|
||||||
|
7
|
||||||
|
8
|
||||||
|
9
|
||||||
|
10
|
||||||
|
"""
|
||||||
|
And I go to the front of the word "text"
|
||||||
|
And I press "C->"
|
||||||
|
And I press "C-'"
|
||||||
|
Then I should have 2 cursors
|
||||||
|
Then I should see exactly:
|
||||||
|
"""
|
||||||
|
|
||||||
|
4
|
||||||
|
5
|
||||||
|
text
|
||||||
|
6
|
||||||
|
7
|
||||||
|
8
|
||||||
|
|
||||||
|
"""
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
Feature: Insert increasing letters
|
||||||
|
|
||||||
|
Scenario: Three cursors, a-b-c
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text)"
|
||||||
|
When I press "H-3"
|
||||||
|
And I press "SPC"
|
||||||
|
Then I should see "This a text contains the word b text thrice (c text)"
|
||||||
|
|
||||||
|
Scenario: Three cursors, j-k-l
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text)"
|
||||||
|
When I press "C-9 H-3"
|
||||||
|
And I press "SPC"
|
||||||
|
Then I should see "This j text contains the word k text thrice (l text)"
|
||||||
|
|
||||||
|
Scenario: Three cursors, z-aa-ab
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text)"
|
||||||
|
When I press "C-u 2 5 H-3"
|
||||||
|
And I press "SPC"
|
||||||
|
Then I should see "This z text contains the word aa text thrice (ab text)"
|
||||||
|
|
||||||
|
Scenario: Three cursors, a-b-c
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text)"
|
||||||
|
When I press "C-u H-3"
|
||||||
|
And I press "SPC"
|
||||||
|
Then I should see "This e text contains the word f text thrice (g text)"
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
Feature: Insert increasing numbers
|
||||||
|
|
||||||
|
Scenario: Three cursors, 0-1-2
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text)"
|
||||||
|
When I press "H-0"
|
||||||
|
And I press "SPC"
|
||||||
|
Then I should see "This 0 text contains the word 1 text thrice (2 text)"
|
||||||
|
|
||||||
|
Scenario: Three cursors, 9-10-11
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text)"
|
||||||
|
When I press "C-9 H-0"
|
||||||
|
And I press "SPC"
|
||||||
|
Then I should see "This 9 text contains the word 10 text thrice (11 text)"
|
||||||
|
|
||||||
|
Scenario: Three cursors, 9-10-11
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text)"
|
||||||
|
When I press "C-u H-0"
|
||||||
|
And I press "SPC"
|
||||||
|
Then I should see "This 4 text contains the word 5 text thrice (6 text)"
|
||||||
|
|
||||||
|
Scenario: Three cursors, 0-1-2, default
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text)"
|
||||||
|
When I set mc/insert-numbers-default to 1
|
||||||
|
And I press "H-0"
|
||||||
|
And I press "SPC"
|
||||||
|
Then I should see "This 1 text contains the word 2 text thrice (3 text)"
|
||||||
|
|
||||||
|
Scenario: Three cursors, 9-10-11, default
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text)"
|
||||||
|
When I set mc/insert-numbers-default to 1
|
||||||
|
And I press "C-9 H-0"
|
||||||
|
And I press "SPC"
|
||||||
|
Then I should see "This 9 text contains the word 10 text thrice (11 text)"
|
||||||
|
|
||||||
|
Scenario: Three cursors, 9-10-11, default
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text)"
|
||||||
|
When I set mc/insert-numbers-default to 1
|
||||||
|
And I press "C-u H-0"
|
||||||
|
And I press "SPC"
|
||||||
|
Then I should see "This 4 text contains the word 5 text thrice (6 text)"
|
||||||
@@ -1,31 +1,36 @@
|
|||||||
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))
|
||||||
"""
|
|
||||||
When I go to the end of the word "abc"
|
|
||||||
And I press "M-f"
|
|
||||||
And I press "M-$"
|
|
||||||
And I type "hmm"
|
|
||||||
Then I should see:
|
|
||||||
"""
|
|
||||||
(defun abc (hmm) (message hmm))
|
|
||||||
(defun def (ghi) (message some-other-ghi))
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
Scenario: Mark symbols in defun
|
||||||
|
When I go to the end of the word "abc"
|
||||||
|
And I press "M-f"
|
||||||
|
And I press "M-$"
|
||||||
|
And I type "hmm"
|
||||||
|
Then I should see:
|
||||||
|
"""
|
||||||
|
(defun abc (hmm) (message hmm))
|
||||||
|
(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))
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -14,6 +14,14 @@ Feature: Marking multiple parts of the buffer
|
|||||||
And I type "sentence"
|
And I type "sentence"
|
||||||
Then I should see "This sentence has the word sentence in it"
|
Then I should see "This sentence has the word sentence in it"
|
||||||
|
|
||||||
|
Scenario: Marking next like this, word
|
||||||
|
Given I turn on delete-selection-mode
|
||||||
|
When I insert "This text has the word text in it"
|
||||||
|
And I go to word "text"
|
||||||
|
And I press "C-S-c C->"
|
||||||
|
And I type "sentence"
|
||||||
|
Then I should see "This sentence has the word sentence in it"
|
||||||
|
|
||||||
Scenario: Skipping a mark
|
Scenario: Skipping a mark
|
||||||
Given I turn on delete-selection-mode
|
Given I turn on delete-selection-mode
|
||||||
When I insert "Here's text, text and text"
|
When I insert "Here's text, text and text"
|
||||||
@@ -54,6 +62,14 @@ Feature: Marking multiple parts of the buffer
|
|||||||
And I type "sentence"
|
And I type "sentence"
|
||||||
Then I should see "This sentence has the word sentence in it"
|
Then I should see "This sentence has the word sentence in it"
|
||||||
|
|
||||||
|
Scenario: Marking prev like this, word
|
||||||
|
Given I turn on delete-selection-mode
|
||||||
|
When I insert "This text has the word text in it"
|
||||||
|
And I go to last word "text"
|
||||||
|
And I press "C-S-c C-<"
|
||||||
|
And I type "sentence"
|
||||||
|
Then I should see "This sentence has the word sentence in it"
|
||||||
|
|
||||||
Scenario: Skipping a prev mark
|
Scenario: Skipping a prev mark
|
||||||
Given I turn on delete-selection-mode
|
Given I turn on delete-selection-mode
|
||||||
When I insert "Here's text, text and text"
|
When I insert "Here's text, text and text"
|
||||||
@@ -132,3 +148,13 @@ Feature: Marking multiple parts of the buffer
|
|||||||
b_bb
|
b_bb
|
||||||
c_cc
|
c_cc
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
Scenario: Multiple cursor with shift selection
|
||||||
|
When I insert "This text contains the word text twice"
|
||||||
|
And I go to the front of the word "text"
|
||||||
|
And I press "M-S-f"
|
||||||
|
And I press "C->"
|
||||||
|
And I press "C-f"
|
||||||
|
And I press "<deletechar>"
|
||||||
|
Then I should see "This text ontains the word text wice"
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
"""
|
||||||
@@ -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))
|
||||||
|
"""
|
||||||
@@ -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"
|
||||||
@@ -166,9 +166,23 @@ Feature: Multiple cursors core
|
|||||||
And I press "C-v"
|
And I press "C-v"
|
||||||
Then the cursor should be at point "8"
|
Then the cursor should be at point "8"
|
||||||
|
|
||||||
|
Scenario: Looping forwards around cursors including one at point-max
|
||||||
|
Given I have cursors at "_" in "1_34_67_"
|
||||||
|
And I press "C-f"
|
||||||
|
And I press "C-v"
|
||||||
|
And I press "C-v"
|
||||||
|
And I press "C-v"
|
||||||
|
Then the cursor should be at point "3"
|
||||||
|
|
||||||
Scenario: Looping backwards around cursors
|
Scenario: Looping backwards around cursors
|
||||||
Given I have cursors at "_" in "1_34567_9"
|
Given I have cursors at "_" in "1_34567_9"
|
||||||
And I press "M-v"
|
And I press "M-v"
|
||||||
And I press "M-v"
|
And I press "M-v"
|
||||||
Then the cursor should be at point "2"
|
Then the cursor should be at point "2"
|
||||||
|
|
||||||
|
Scenario: Looping backwards around cursors including one at point-min
|
||||||
|
Given I have cursors at "_" in "_234_67_9"
|
||||||
|
And I press "M-v"
|
||||||
|
And I press "M-v"
|
||||||
|
And I press "M-v"
|
||||||
|
Then the cursor should be at point "1"
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
Feature: Repeat last interactive command for fake cursors (mc/repeat-command)
|
||||||
|
|
||||||
|
Scenario: Clone insert-char from M-x
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text)"
|
||||||
|
When I start an action chain
|
||||||
|
When I press "M-x"
|
||||||
|
And I type "insert-char"
|
||||||
|
And I press "RET"
|
||||||
|
And I type "21"
|
||||||
|
And I press "RET"
|
||||||
|
And I press "C-:"
|
||||||
|
And I press "y"
|
||||||
|
And I execute the action chain
|
||||||
|
Then I should see "This !text contains the word !text thrice (!text)"
|
||||||
|
|
||||||
|
Scenario: Clone insert-char from M-:
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text)"
|
||||||
|
When I start an action chain
|
||||||
|
When I press "M-:"
|
||||||
|
And I type "(insert-char (+ 40 2))"
|
||||||
|
And I press "RET"
|
||||||
|
And I press "C-:"
|
||||||
|
And I press "y"
|
||||||
|
And I execute the action chain
|
||||||
|
Then I should see "This *text contains the word *text thrice (*text)"
|
||||||
|
|
||||||
|
Scenario: Disable prompt
|
||||||
|
Given I have cursors at "text" in "This text/0000 contains the word text/1111 thrice (text/2222)"
|
||||||
|
When I set mc/always-repeat-command to t
|
||||||
|
When I start an action chain
|
||||||
|
And I press "M-x"
|
||||||
|
And I type "zap-to-char"
|
||||||
|
And I press "RET"
|
||||||
|
And I press "/"
|
||||||
|
And I press "C-:"
|
||||||
|
And I execute the action chain
|
||||||
|
Then I should see "This 0000 contains the word 1111 thrice (2222)"
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
Feature: Sorting and reversing cursor regions
|
||||||
|
|
||||||
|
Scenario: Reversing regions
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text here)"
|
||||||
|
When I press "M-f"
|
||||||
|
And I press "C-f"
|
||||||
|
And I press "C-SPC"
|
||||||
|
And I press "M-f"
|
||||||
|
And I press "H-1"
|
||||||
|
Then I should see "This text here the word text thrice (text contains)"
|
||||||
|
|
||||||
|
Scenario: Sorting regions
|
||||||
|
Given I have cursors at "text" in "This text contains the word text thrice (text here)"
|
||||||
|
When I press "M-f"
|
||||||
|
And I press "C-f"
|
||||||
|
And I press "C-SPC"
|
||||||
|
And I press "M-f"
|
||||||
|
And I press "H-2"
|
||||||
|
Then I should see "This text contains the word text here (text thrice)"
|
||||||
@@ -1,29 +1,80 @@
|
|||||||
|
(require 'cl) ;; For lexical-let
|
||||||
|
|
||||||
|
(When "^I mark next like this$"
|
||||||
|
(lambda () (call-interactively 'mc/mark-next-like-this)))
|
||||||
|
|
||||||
|
(When "^I mark next like this word$"
|
||||||
|
(lambda () (call-interactively 'mc/mark-next-like-this-word)))
|
||||||
|
|
||||||
|
(When "^I mark next like this symbol$"
|
||||||
|
(lambda () (call-interactively 'mc/mark-next-like-this-symbol)))
|
||||||
|
|
||||||
|
(When "^I mark previous like this$"
|
||||||
|
(lambda () (call-interactively 'mc/mark-previous-like-this)))
|
||||||
|
|
||||||
|
(When "^I mark previous like this word$"
|
||||||
|
(lambda () (call-interactively 'mc/mark-previous-like-this-word)))
|
||||||
|
|
||||||
|
(When "^I mark previous like this symbol$"
|
||||||
|
(lambda () (call-interactively 'mc/mark-previous-like-this-symbol)))
|
||||||
|
|
||||||
|
(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 insert letters$"
|
||||||
|
(lambda () (call-interactively 'mc/insert-letters)))
|
||||||
|
|
||||||
|
(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)))
|
||||||
(assert (eq (string-to-number num) actual) nil
|
(cl-assert (eq (string-to-number num) actual) nil
|
||||||
"Expected to have %s cursors, but was %d." num actual))))
|
"Expected to have %s cursors, but was %d." num actual))))
|
||||||
|
|
||||||
(Then "^I should have one cursor$"
|
(Then "^I should have one cursor$"
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(assert (not multiple-cursors-mode) nil
|
(cl-assert (not multiple-cursors-mode) nil
|
||||||
"Expected to have one cursor, but multiple-cursors-mode is still active.")
|
"Expected to have one cursor, but multiple-cursors-mode is still active.")
|
||||||
(assert (eq 1 (mc/num-cursors)) nil
|
(cl-assert (eq 1 (mc/num-cursors)) nil
|
||||||
"Expected to have one cursor, but there are still fake cursor overlays.")))
|
"Expected to have one cursor, but there are still fake cursor overlays.")))
|
||||||
|
|
||||||
(Then "^rectangular-region-mode should be off$"
|
(Then "^rectangular-region-mode should be off$"
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(assert (not rectangular-region-mode) nil
|
(cl-assert (not rectangular-region-mode) nil
|
||||||
"Expected rectangular-region-mode mode to be off, but wasn't.")))
|
"Expected rectangular-region-mode mode to be off, but wasn't.")))
|
||||||
|
|
||||||
(Then "^rectangular-region-mode should be on$"
|
(Then "^rectangular-region-mode should be on$"
|
||||||
(lambda ()
|
(lambda ()
|
||||||
(assert rectangular-region-mode nil
|
(cl-assert rectangular-region-mode nil
|
||||||
"Expected rectangular-region-mode mode to be on, but wasn't.")))
|
"Expected rectangular-region-mode mode to be on, but wasn't.")))
|
||||||
|
|
||||||
(When "^I press \"\\(.+\\)\"$"
|
(When "^I press \"\\(.+\\)\"$"
|
||||||
(lambda (keybinding)
|
(lambda (keybinding)
|
||||||
@@ -45,6 +96,17 @@
|
|||||||
(mc/mark-all-like-this)
|
(mc/mark-all-like-this)
|
||||||
(mc/keyboard-quit)))
|
(mc/keyboard-quit)))
|
||||||
|
|
||||||
|
(Given "^I have cursors at \"\\(.+\\)\" in \\(?: \"\\(.+\\)\"\\|:\\)$"
|
||||||
|
(lambda (needle haystack)
|
||||||
|
(insert haystack)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(search-forward needle)
|
||||||
|
(set-mark (point))
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(mc/mark-all-like-this)
|
||||||
|
(mc/keyboard-quit)))
|
||||||
|
|
||||||
|
|
||||||
(When "^I copy \"\\(.+\\)\" in another program$"
|
(When "^I copy \"\\(.+\\)\" in another program$"
|
||||||
(lambda (text)
|
(lambda (text)
|
||||||
(lexical-let ((text text))
|
(lexical-let ((text text))
|
||||||
@@ -78,20 +140,55 @@
|
|||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(let ((search (re-search-forward (format "%s" char) nil t))
|
(let ((search (re-search-forward (format "%s" char) nil t))
|
||||||
(message "Can not go to character '%s' since it does not exist in the current buffer: %s"))
|
(message "Can not go to character '%s' since it does not exist in the current buffer: %s"))
|
||||||
(assert search nil message char (espuds-buffer-contents)))))
|
(cl-assert search nil message char (espuds-buffer-contents)))))
|
||||||
|
|
||||||
(When "^I go to the \\(front\\|end\\) of the word \"\\(.+\\)\"$"
|
(When "^I go to the \\(front\\|end\\) of the word \"\\(.+\\)\"$"
|
||||||
(lambda (pos word)
|
(lambda (pos word)
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(let ((search (re-search-forward (format "%s" word) nil t))
|
(let ((search (re-search-forward (format "%s" word) nil t))
|
||||||
(message "Can not go to character '%s' since it does not exist in the current buffer: %s"))
|
(message "Can not go to character '%s' since it does not exist in the current buffer: %s"))
|
||||||
(assert search nil message word (espuds-buffer-contents))
|
(cl-assert search nil message word (espuds-buffer-contents))
|
||||||
(if (string-equal "front" pos) (backward-word)))))
|
(if (string-equal "front" pos) (backward-word)))))
|
||||||
|
|
||||||
|
(When "^I go to last word \"\\(.+\\)\"$"
|
||||||
|
(lambda (text)
|
||||||
|
(goto-char (point-max))
|
||||||
|
(let ((search (re-search-backward text nil t)))
|
||||||
|
(cl-assert search nil "The text '%s' was not found in the current buffer." text))))
|
||||||
|
|
||||||
(When "^I select the last \"\\(.+\\)\"$"
|
(When "^I select the last \"\\(.+\\)\"$"
|
||||||
(lambda (text)
|
(lambda (text)
|
||||||
(goto-char (point-max))
|
(goto-char (point-max))
|
||||||
(let ((search (re-search-backward text nil t)))
|
(let ((search (re-search-backward text nil t)))
|
||||||
(assert search nil "The text '%s' was not found in the current buffer." text))
|
(cl-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))))
|
||||||
|
|
||||||
|
(Then "^I should see exactly\\(?: \"\\(.+\\)\"\\|:\\)$"
|
||||||
|
"Asserts that the current buffer does not include some text with
|
||||||
|
respect of text hidden by overlays"
|
||||||
|
(lambda (expected)
|
||||||
|
(let ((p (point-min))
|
||||||
|
(visible-text "")
|
||||||
|
(message "Expected '%s' to be part of '%s', but was not found in current buffer.")
|
||||||
|
)
|
||||||
|
(while (not (= p (point-max)))
|
||||||
|
(if (not (invisible-p p))
|
||||||
|
(setq visible-text (concat visible-text (buffer-substring p (1+ p))))
|
||||||
|
)
|
||||||
|
(setq p (1+ p))
|
||||||
|
)
|
||||||
|
(cl-assert (s-equals? expected visible-text) nil message expected visible-text))))
|
||||||
|
|
||||||
|
|
||||||
|
;; Local Variables:
|
||||||
|
;; byte-compile-warnings: (not cl-functions)
|
||||||
|
;; End:
|
||||||
|
|||||||
@@ -21,10 +21,19 @@
|
|||||||
(multiple-cursors-mode 0)
|
(multiple-cursors-mode 0)
|
||||||
(rectangular-region-mode 0)
|
(rectangular-region-mode 0)
|
||||||
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
|
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
|
||||||
|
(global-set-key (kbd "C-S-c C->") 'mc/mark-next-like-this-word)
|
||||||
|
(global-set-key (kbd "C-S-c M->") 'mc/mark-next-like-this-symbol)
|
||||||
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
|
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
|
||||||
|
(global-set-key (kbd "C-S-c C-<") 'mc/mark-previous-like-this-word)
|
||||||
|
(global-set-key (kbd "C-S-c M-<") 'mc/mark-previous-like-this-symbol)
|
||||||
(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-3") 'mc/insert-letters)
|
||||||
|
(global-set-key (kbd "H-1") 'mc/reverse-regions)
|
||||||
|
(global-set-key (kbd "H-2") 'mc/sort-regions)
|
||||||
(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
|
(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
|
||||||
(global-set-key (kbd "H-SPC") 'set-rectangular-region-anchor)
|
(global-set-key (kbd "H-SPC") 'set-rectangular-region-anchor)
|
||||||
(switch-to-buffer
|
(switch-to-buffer
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
Feature: Align cursors with whitespaces
|
||||||
|
|
||||||
|
Scenario: Vertical aligning with `x'
|
||||||
|
Given I have cursors at "word" in :
|
||||||
|
"""
|
||||||
|
One word
|
||||||
|
Another word
|
||||||
|
"""
|
||||||
|
And I press "<<mc/vertical-align>> \170"
|
||||||
|
Then I should see:
|
||||||
|
"""
|
||||||
|
One xxxxword
|
||||||
|
Another word
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Vertical aligning with space
|
||||||
|
Given I have cursors at "word" in :
|
||||||
|
"""
|
||||||
|
One word
|
||||||
|
Another word
|
||||||
|
"""
|
||||||
|
And I press "<<mc/vertical-align-with-space>>"
|
||||||
|
Then I should see:
|
||||||
|
"""
|
||||||
|
One word
|
||||||
|
Another word
|
||||||
|
"""
|
||||||
+15
-18
@@ -1,6 +1,6 @@
|
|||||||
;;; mc-cycle-cursors.el
|
;;; mc-cycle-cursors.el
|
||||||
|
|
||||||
;; Copyright (C) 2012 Magnar Sveen
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||||
;; Keywords: editing cursors
|
;; Keywords: editing cursors
|
||||||
@@ -28,11 +28,9 @@
|
|||||||
|
|
||||||
(require 'multiple-cursors-core)
|
(require 'multiple-cursors-core)
|
||||||
|
|
||||||
(eval-when-compile (require 'cl))
|
|
||||||
|
|
||||||
(defun mc/next-fake-cursor-after-point ()
|
(defun mc/next-fake-cursor-after-point ()
|
||||||
(let ((pos (point))
|
(let ((pos (point))
|
||||||
(next-pos (point-max))
|
(next-pos (1+ (point-max)))
|
||||||
next)
|
next)
|
||||||
(mc/for-each-fake-cursor
|
(mc/for-each-fake-cursor
|
||||||
(let ((cursor-pos (overlay-get cursor 'point)))
|
(let ((cursor-pos (overlay-get cursor 'point)))
|
||||||
@@ -44,7 +42,7 @@
|
|||||||
|
|
||||||
(defun mc/prev-fake-cursor-before-point ()
|
(defun mc/prev-fake-cursor-before-point ()
|
||||||
(let ((pos (point))
|
(let ((pos (point))
|
||||||
(prev-pos (point-min))
|
(prev-pos (1- (point-min)))
|
||||||
prev)
|
prev)
|
||||||
(mc/for-each-fake-cursor
|
(mc/for-each-fake-cursor
|
||||||
(let ((cursor-pos (overlay-get cursor 'point)))
|
(let ((cursor-pos (overlay-get cursor 'point)))
|
||||||
@@ -63,7 +61,7 @@
|
|||||||
:group 'multiple-cursors)
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
(defun mc/handle-loop-condition (error-message)
|
(defun mc/handle-loop-condition (error-message)
|
||||||
(ecase mc/cycle-looping-behaviour
|
(cl-ecase mc/cycle-looping-behaviour
|
||||||
(error (error error-message))
|
(error (error error-message))
|
||||||
(warn (message error-message))
|
(warn (message error-message))
|
||||||
(continue 'continue)
|
(continue 'continue)
|
||||||
@@ -72,22 +70,22 @@
|
|||||||
(defun mc/first-fake-cursor-after (point)
|
(defun mc/first-fake-cursor-after (point)
|
||||||
"Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)."
|
"Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)."
|
||||||
(let* ((cursors (mc/all-fake-cursors))
|
(let* ((cursors (mc/all-fake-cursors))
|
||||||
(cursors-after-point (remove-if (lambda (cursor)
|
(cursors-after-point (cl-remove-if (lambda (cursor)
|
||||||
(< (mc/cursor-beg cursor) point))
|
(< (mc/cursor-beg cursor) point))
|
||||||
cursors))
|
cursors))
|
||||||
(cursors-in-order (sort* cursors-after-point '< :key 'mc/cursor-beg)))
|
(cursors-in-order (cl-sort cursors-after-point '< :key 'mc/cursor-beg)))
|
||||||
(first cursors-in-order)))
|
(car cursors-in-order)))
|
||||||
|
|
||||||
(defun mc/last-fake-cursor-before (point)
|
(defun mc/last-fake-cursor-before (point)
|
||||||
"Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)."
|
"Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)."
|
||||||
(let* ((cursors (mc/all-fake-cursors))
|
(let* ((cursors (mc/all-fake-cursors))
|
||||||
(cursors-before-point (remove-if (lambda (cursor)
|
(cursors-before-point (cl-remove-if (lambda (cursor)
|
||||||
(> (mc/cursor-end cursor) point))
|
(> (mc/cursor-end cursor) point))
|
||||||
cursors))
|
cursors))
|
||||||
(cursors-in-order (sort* cursors-before-point '> :key 'mc/cursor-end)))
|
(cursors-in-order (cl-sort cursors-before-point '> :key 'mc/cursor-end)))
|
||||||
(first cursors-in-order)))
|
(car cursors-in-order)))
|
||||||
|
|
||||||
(defun* mc/cycle (next-cursor fallback-cursor loop-message)
|
(cl-defun mc/cycle (next-cursor fallback-cursor loop-message)
|
||||||
(when (null next-cursor)
|
(when (null next-cursor)
|
||||||
(when (eql 'stop (mc/handle-loop-condition loop-message))
|
(when (eql 'stop (mc/handle-loop-condition loop-message))
|
||||||
(return-from mc/cycle nil))
|
(return-from mc/cycle nil))
|
||||||
@@ -116,7 +114,6 @@
|
|||||||
|
|
||||||
;; Local Variables:
|
;; Local Variables:
|
||||||
;; coding: utf-8
|
;; coding: utf-8
|
||||||
;; byte-compile-warnings: (not cl-functions)
|
|
||||||
;; End:
|
;; End:
|
||||||
|
|
||||||
;;; mc-cycle-cursors.el ends here
|
;;; mc-cycle-cursors.el ends here
|
||||||
|
|||||||
+51
-14
@@ -1,6 +1,6 @@
|
|||||||
;;; mc-edit-lines.el
|
;;; mc-edit-lines.el
|
||||||
|
|
||||||
;; Copyright (C) 2012 Magnar Sveen
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||||
;; Keywords: editing cursors
|
;; Keywords: editing cursors
|
||||||
@@ -29,26 +29,65 @@
|
|||||||
|
|
||||||
(require 'multiple-cursors-core)
|
(require 'multiple-cursors-core)
|
||||||
|
|
||||||
|
(defcustom mc/edit-lines-empty-lines nil
|
||||||
|
"What should be done by `mc/edit-lines' when a line is not long enough."
|
||||||
|
:type '(radio (const :tag "Pad the line with spaces." pad)
|
||||||
|
(const :tag "Ignore the line." ignore)
|
||||||
|
(const :tag "Signal an error." error)
|
||||||
|
(const :tag "Nothing. Cursor is at end of line." nil))
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/edit-lines ()
|
(defun mc/edit-lines (&optional arg)
|
||||||
"Add one cursor to each line of the active region.
|
"Add one cursor to each line of the active region.
|
||||||
Starts from mark and moves in straight down or up towards the
|
Starts from mark and moves in straight down or up towards the
|
||||||
line point is on."
|
line point is on.
|
||||||
(interactive)
|
|
||||||
(when (not (use-region-p))
|
What is done with lines which are not long enough is governed by
|
||||||
(error "Mark a set of lines first."))
|
`mc/edit-lines-empty-lines'. The prefix argument ARG can be used
|
||||||
|
to override this. If ARG is a symbol (when called from Lisp),
|
||||||
|
that symbol is used instead of `mc/edit-lines-empty-lines'.
|
||||||
|
Otherwise, if ARG negative, short lines will be ignored. Any
|
||||||
|
other non-nil value will cause short lines to be padded."
|
||||||
|
(interactive "P")
|
||||||
|
(when (not (and mark-active (/= (point) (mark))))
|
||||||
|
(error "Mark a set of lines first"))
|
||||||
(mc/remove-fake-cursors)
|
(mc/remove-fake-cursors)
|
||||||
(let* ((col (current-column))
|
(let* ((col (current-column))
|
||||||
(point-line (line-number-at-pos))
|
(point-line (line-number-at-pos))
|
||||||
(mark-line (progn (exchange-point-and-mark) (line-number-at-pos)))
|
(mark-line (progn (exchange-point-and-mark) (line-number-at-pos)))
|
||||||
(direction (if (< point-line mark-line) :up :down)))
|
(direction (if (< point-line mark-line) :up :down))
|
||||||
|
(style (cond
|
||||||
|
;; called from lisp
|
||||||
|
((and arg (symbolp arg))
|
||||||
|
arg)
|
||||||
|
;; negative argument
|
||||||
|
((< (prefix-numeric-value arg) 0)
|
||||||
|
'ignore)
|
||||||
|
(arg 'pad)
|
||||||
|
(t mc/edit-lines-empty-lines))))
|
||||||
(deactivate-mark)
|
(deactivate-mark)
|
||||||
(when (and (eq direction :up) (bolp))
|
(when (and (eq direction :up) (bolp))
|
||||||
(forward-line -1)
|
(previous-logical-line 1 nil)
|
||||||
(move-to-column col))
|
(move-to-column col))
|
||||||
|
;; Add the cursors
|
||||||
(while (not (eq (line-number-at-pos) point-line))
|
(while (not (eq (line-number-at-pos) point-line))
|
||||||
(mc/create-fake-cursor-at-point)
|
;; Pad the line
|
||||||
(if (eq direction :up) (forward-line -1) (forward-line 1))
|
(when (eq style 'pad)
|
||||||
|
(while (< (current-column) col)
|
||||||
|
(insert " ")))
|
||||||
|
;; Error
|
||||||
|
(when (and (eq style 'error)
|
||||||
|
(not (equal col (current-column))))
|
||||||
|
(error "Short line encountered in `mc/edit-lines'"))
|
||||||
|
;; create the cursor
|
||||||
|
(unless (and (eq style 'ignore)
|
||||||
|
(not (equal col (current-column))))
|
||||||
|
(mc/create-fake-cursor-at-point))
|
||||||
|
;; proceed to next
|
||||||
|
(if (eq direction :up)
|
||||||
|
(previous-logical-line 1 nil)
|
||||||
|
(next-logical-line 1 nil))
|
||||||
(move-to-column col))
|
(move-to-column col))
|
||||||
(multiple-cursors-mode)))
|
(multiple-cursors-mode)))
|
||||||
|
|
||||||
@@ -57,16 +96,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)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,107 @@
|
|||||||
|
;;; mc-hide-unmatched-lines.el
|
||||||
|
|
||||||
|
;; Copyright (C) 2014 Aleksey Fedotov
|
||||||
|
|
||||||
|
;; Author: Aleksey Fedotov <lexa@cfotr.com>
|
||||||
|
;; Keywords: editing cursors
|
||||||
|
|
||||||
|
;; 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 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; This minor mode when enabled hides all lines where no cursors (and
|
||||||
|
;; also hum/lines-to-expand below and above) To make use of this mode
|
||||||
|
;; press "C-'" while multiple-cursor-mode is active. You can still
|
||||||
|
;; edit lines while you are in mc-hide-unmatched-lines mode. To leave
|
||||||
|
;; this mode press "<return>" or "C-g"
|
||||||
|
;;
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(require 'multiple-cursors-core)
|
||||||
|
(require 'mc-mark-more)
|
||||||
|
|
||||||
|
(defvar hum/hide-unmatched-lines-mode-map (make-sparse-keymap)
|
||||||
|
"Keymap for hide unmatched lines is mainly for rebinding C-g")
|
||||||
|
|
||||||
|
(define-key hum/hide-unmatched-lines-mode-map (kbd "C-g") 'hum/keyboard-quit)
|
||||||
|
(define-key hum/hide-unmatched-lines-mode-map (kbd "<return>") 'hum/keyboard-quit)
|
||||||
|
|
||||||
|
(defun hum/keyboard-quit ()
|
||||||
|
"Leave hide-unmatched-lines mode"
|
||||||
|
(interactive)
|
||||||
|
(mc-hide-unmatched-lines-mode 0))
|
||||||
|
|
||||||
|
;; used only in in multiple-cursors-mode-disabled-hook
|
||||||
|
(defun hum/disable-hum-mode ()
|
||||||
|
(mc-hide-unmatched-lines-mode 0))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(define-minor-mode mc-hide-unmatched-lines-mode
|
||||||
|
"Minor mode when enabled hides all lines where no cursors (and
|
||||||
|
also hum/lines-to-expand below and above) To make use of this
|
||||||
|
mode press \"C-'\" while multiple-cursor-mode is active. You can
|
||||||
|
still edit lines while you are in mc-hide-unmatched-lines
|
||||||
|
mode. To leave this mode press <return> or \"C-g\""
|
||||||
|
nil " hu"
|
||||||
|
hum/hide-unmatched-lines-mode-map
|
||||||
|
(if mc-hide-unmatched-lines-mode
|
||||||
|
;;just in case if mc mode will be disabled while hide-unmatched-lines is active
|
||||||
|
(progn
|
||||||
|
(hum/hide-unmatched-lines)
|
||||||
|
(add-hook 'multiple-cursors-mode-disabled-hook 'hum/disable-hum-mode t t))
|
||||||
|
(progn
|
||||||
|
(hum/unhide-unmatched-lines)
|
||||||
|
(remove-hook 'multiple-cursors-mode-disabled-hook 'hum/disable-hum-mode))))
|
||||||
|
|
||||||
|
(defconst hum/invisible-overlay-name 'hum/invisible-overlay-name)
|
||||||
|
|
||||||
|
(defcustom hum/lines-to-expand 2
|
||||||
|
"How many lines below and above cursor to show"
|
||||||
|
:type '(integer)
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
|
(defcustom hum/placeholder "..."
|
||||||
|
"Placeholder which will be placed insted of hiden text"
|
||||||
|
:type '(string)
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
|
(defun hum/add-invisible-overlay (begin end)
|
||||||
|
(let ((overlay (make-overlay begin
|
||||||
|
end
|
||||||
|
(current-buffer)
|
||||||
|
t
|
||||||
|
nil
|
||||||
|
)))
|
||||||
|
(overlay-put overlay hum/invisible-overlay-name t)
|
||||||
|
(overlay-put overlay 'invisible t)
|
||||||
|
(overlay-put overlay 'intangible t)
|
||||||
|
(overlay-put overlay 'evaporate t)
|
||||||
|
(overlay-put overlay 'after-string hum/placeholder)))
|
||||||
|
|
||||||
|
(defun hum/hide-unmatched-lines ()
|
||||||
|
(let ((begin (point-min)))
|
||||||
|
(mc/for-each-cursor-ordered
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (mc/cursor-beg cursor))
|
||||||
|
(if (< begin (line-beginning-position (- hum/lines-to-expand)))
|
||||||
|
(hum/add-invisible-overlay begin (line-end-position (- hum/lines-to-expand))))
|
||||||
|
(setq begin (line-beginning-position (+ 2 hum/lines-to-expand)))))
|
||||||
|
(hum/add-invisible-overlay begin (point-max))))
|
||||||
|
|
||||||
|
(defun hum/unhide-unmatched-lines ()
|
||||||
|
(remove-overlays nil nil hum/invisible-overlay-name t))
|
||||||
|
|
||||||
|
(provide 'mc-hide-unmatched-lines-mode)
|
||||||
|
(define-key mc/keymap (kbd "C-'") 'mc-hide-unmatched-lines-mode)
|
||||||
+399
-96
@@ -1,6 +1,6 @@
|
|||||||
;;; mc-mark-more.el
|
;;; mc-mark-more.el
|
||||||
|
|
||||||
;; Copyright (C) 2012 Magnar Sveen
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||||
;; Keywords: editing cursors
|
;; Keywords: editing cursors
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
beg))
|
beg))
|
||||||
|
|
||||||
(defun mc/furthest-cursor-before-point ()
|
(defun mc/furthest-cursor-before-point ()
|
||||||
(let ((beg (min (mark) (point)))
|
(let ((beg (if mark-active (min (mark) (point)) (point)))
|
||||||
furthest)
|
furthest)
|
||||||
(mc/for-each-fake-cursor
|
(mc/for-each-fake-cursor
|
||||||
(when (< (mc/cursor-beg cursor) beg)
|
(when (< (mc/cursor-beg cursor) beg)
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
furthest))
|
furthest))
|
||||||
|
|
||||||
(defun mc/furthest-cursor-after-point ()
|
(defun mc/furthest-cursor-after-point ()
|
||||||
(let ((end (max (mark) (point)))
|
(let ((end (if mark-active (max (mark) (point)) (point)))
|
||||||
furthest)
|
furthest)
|
||||||
(mc/for-each-fake-cursor
|
(mc/for-each-fake-cursor
|
||||||
(when (> (mc/cursor-end cursor) end)
|
(when (> (mc/cursor-end cursor) end)
|
||||||
@@ -72,6 +72,18 @@
|
|||||||
(setq furthest cursor)))
|
(setq furthest cursor)))
|
||||||
furthest))
|
furthest))
|
||||||
|
|
||||||
|
(defun mc/fake-cursor-at-point (&optional point)
|
||||||
|
"Return the fake cursor with its point right at POINT (defaults
|
||||||
|
to (point)), or nil."
|
||||||
|
(setq point (or point (point)))
|
||||||
|
(let ((cursors (mc/all-fake-cursors))
|
||||||
|
(c nil))
|
||||||
|
(catch 'found
|
||||||
|
(while (setq c (pop cursors))
|
||||||
|
(when (eq (marker-position (overlay-get c 'point))
|
||||||
|
point)
|
||||||
|
(throw 'found c))))))
|
||||||
|
|
||||||
(defun mc/region-strings ()
|
(defun mc/region-strings ()
|
||||||
(let ((strings (list (buffer-substring-no-properties (point) (mark)))))
|
(let ((strings (list (buffer-substring-no-properties (point) (mark)))))
|
||||||
(mc/for-each-fake-cursor
|
(mc/for-each-fake-cursor
|
||||||
@@ -92,54 +104,106 @@ Use like case-fold-search, don't recommend setting it globally.")
|
|||||||
(defun mc/mark-more-like-this (skip-last direction)
|
(defun mc/mark-more-like-this (skip-last direction)
|
||||||
(let ((case-fold-search nil)
|
(let ((case-fold-search nil)
|
||||||
(re (regexp-opt (mc/region-strings) mc/enclose-search-term))
|
(re (regexp-opt (mc/region-strings) mc/enclose-search-term))
|
||||||
(point-out-of-order (ecase direction
|
(point-out-of-order (cl-ecase direction
|
||||||
(forwards (< (point) (mark)))
|
(forwards (< (point) (mark)))
|
||||||
(backwards (not (< (point) (mark))))))
|
(backwards (not (< (point) (mark))))))
|
||||||
(furthest-cursor (ecase direction
|
(furthest-cursor (cl-ecase direction
|
||||||
(forwards (mc/furthest-cursor-after-point))
|
(forwards (mc/furthest-cursor-after-point))
|
||||||
(backwards (mc/furthest-cursor-before-point))))
|
(backwards (mc/furthest-cursor-before-point))))
|
||||||
(start-char (ecase direction
|
(start-char (cl-ecase direction
|
||||||
(forwards (mc/furthest-region-end))
|
(forwards (mc/furthest-region-end))
|
||||||
(backwards (mc/first-region-start))))
|
(backwards (mc/first-region-start))))
|
||||||
(search-function (ecase direction
|
(search-function (cl-ecase direction
|
||||||
(forwards 'search-forward-regexp)
|
(forwards 'search-forward-regexp)
|
||||||
(backwards 'search-backward-regexp)))
|
(backwards 'search-backward-regexp)))
|
||||||
(match-point-getter (ecase direction
|
(match-point-getter (cl-ecase direction
|
||||||
(forwards 'match-beginning)
|
(forwards 'match-beginning)
|
||||||
(backwards 'match-end))))
|
(backwards 'match-end))))
|
||||||
(mc/save-excursion
|
(if (and skip-last (not furthest-cursor))
|
||||||
(goto-char start-char)
|
(error "No cursors to be skipped")
|
||||||
(when skip-last
|
(mc/save-excursion
|
||||||
(mc/remove-fake-cursor furthest-cursor))
|
(goto-char start-char)
|
||||||
(if (funcall search-function re nil t)
|
(when skip-last
|
||||||
(progn
|
(mc/remove-fake-cursor furthest-cursor))
|
||||||
(push-mark (funcall match-point-getter 0))
|
(if (funcall search-function re nil t)
|
||||||
(when point-out-of-order
|
(progn
|
||||||
(exchange-point-and-mark))
|
(push-mark (funcall match-point-getter 0))
|
||||||
(mc/create-fake-cursor-at-point))
|
(when point-out-of-order
|
||||||
(error "no more matches found.")))))
|
(exchange-point-and-mark))
|
||||||
|
(mc/create-fake-cursor-at-point))
|
||||||
|
(user-error "no more matches found."))))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-next-like-this (arg)
|
(defun mc/mark-next-like-this (arg)
|
||||||
"Find and mark the next part of the buffer matching the currently active region
|
"Find and mark the next part of the buffer matching the currently active region
|
||||||
|
If no region is active add a cursor on the next line
|
||||||
With negative ARG, delete the last one instead.
|
With negative ARG, delete the last one instead.
|
||||||
With zero ARG, skip the last one and mark next."
|
With zero ARG, skip the last one and mark next."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(if (region-active-p)
|
(if (< arg 0)
|
||||||
(if (< arg 0)
|
(let ((cursor (mc/furthest-cursor-after-point)))
|
||||||
(mc/remove-fake-cursor (mc/furthest-cursor-after-point))
|
(if cursor
|
||||||
(mc/mark-more-like-this (= arg 0) 'forwards))
|
(mc/remove-fake-cursor cursor)
|
||||||
(mc/mark-lines arg 'forwards))
|
(error "No cursors to be unmarked")))
|
||||||
|
(if (region-active-p)
|
||||||
|
(mc/mark-more-like-this (= arg 0) 'forwards)
|
||||||
|
(mc/mark-lines arg 'forwards)))
|
||||||
(mc/maybe-multiple-cursors-mode))
|
(mc/maybe-multiple-cursors-mode))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/mark-next-like-this-word (arg)
|
||||||
|
"Find and mark the next part of the buffer matching the currently active region
|
||||||
|
If no region is active, mark the word at the point and find the next match
|
||||||
|
With negative ARG, delete the last one instead.
|
||||||
|
With zero ARG, skip the last one and mark next."
|
||||||
|
(interactive "p")
|
||||||
|
(if (< arg 0)
|
||||||
|
(let ((cursor (mc/furthest-cursor-after-point)))
|
||||||
|
(if cursor
|
||||||
|
(mc/remove-fake-cursor cursor)
|
||||||
|
(error "No cursors to be unmarked")))
|
||||||
|
(if (region-active-p)
|
||||||
|
(mc/mark-more-like-this (= arg 0) 'forwards)
|
||||||
|
(mc--select-thing-at-point 'word)
|
||||||
|
(mc/mark-more-like-this (= arg 0) 'forwards)))
|
||||||
|
(mc/maybe-multiple-cursors-mode))
|
||||||
|
|
||||||
|
(defun mc/mark-next-like-this-symbol (arg)
|
||||||
|
"Find and mark the next part of the buffer matching the currently active region
|
||||||
|
If no region is active, mark the symbol at the point and find the next match
|
||||||
|
With negative ARG, delete the last one instead.
|
||||||
|
With zero ARG, skip the last one and mark next."
|
||||||
|
(interactive "p")
|
||||||
|
(if (< arg 0)
|
||||||
|
(let ((cursor (mc/furthest-cursor-after-point)))
|
||||||
|
(if cursor
|
||||||
|
(mc/remove-fake-cursor cursor)
|
||||||
|
(error "No cursors to be unmarked")))
|
||||||
|
(if (region-active-p)
|
||||||
|
(mc/mark-more-like-this (= arg 0) 'forwards)
|
||||||
|
(mc--select-thing-at-point 'symbol)
|
||||||
|
(mc/mark-more-like-this (= arg 0) 'forwards)))
|
||||||
|
(mc/maybe-multiple-cursors-mode))
|
||||||
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-next-word-like-this (arg)
|
(defun mc/mark-next-word-like-this (arg)
|
||||||
|
"Find and mark the next word of the buffer matching the currently active region
|
||||||
|
The matching region must be a whole word to be a match
|
||||||
|
If no region is active, mark the symbol at the point and find the next match
|
||||||
|
With negative ARG, delete the last one instead.
|
||||||
|
With zero ARG, skip the last one and mark next."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(let ((mc/enclose-search-term 'words))
|
(let ((mc/enclose-search-term 'words))
|
||||||
(mc/mark-next-like-this arg)))
|
(mc/mark-next-like-this arg)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-next-symbol-like-this (arg)
|
(defun mc/mark-next-symbol-like-this (arg)
|
||||||
|
"Find and mark the next symbol of the buffer matching the currently active region
|
||||||
|
The matching region must be a whole symbol to be a match
|
||||||
|
If no region is active, mark the symbol at the point and find the next match
|
||||||
|
With negative ARG, delete the last one instead.
|
||||||
|
With zero ARG, skip the last one and mark next."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(let ((mc/enclose-search-term 'symbols))
|
(let ((mc/enclose-search-term 'symbols))
|
||||||
(mc/mark-next-like-this arg)))
|
(mc/mark-next-like-this arg)))
|
||||||
@@ -147,36 +211,92 @@ With zero ARG, skip the last one and mark next."
|
|||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-previous-like-this (arg)
|
(defun mc/mark-previous-like-this (arg)
|
||||||
"Find and mark the previous part of the buffer matching the currently active region
|
"Find and mark the previous part of the buffer matching the currently active region
|
||||||
|
If no region is active add a cursor on the previous line
|
||||||
With negative ARG, delete the last one instead.
|
With negative ARG, delete the last one instead.
|
||||||
With zero ARG, skip the last one and mark next."
|
With zero ARG, skip the last one and mark next."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(if (region-active-p)
|
(if (< arg 0)
|
||||||
(if (< arg 0)
|
(let ((cursor (mc/furthest-cursor-before-point)))
|
||||||
(mc/remove-fake-cursor (mc/furthest-cursor-before-point))
|
(if cursor
|
||||||
(mc/mark-more-like-this (= arg 0) 'backwards))
|
(mc/remove-fake-cursor cursor)
|
||||||
(mc/mark-lines arg 'backwards))
|
(error "No cursors to be unmarked")))
|
||||||
|
(if (region-active-p)
|
||||||
|
(mc/mark-more-like-this (= arg 0) 'backwards)
|
||||||
|
(mc/mark-lines arg 'backwards)))
|
||||||
(mc/maybe-multiple-cursors-mode))
|
(mc/maybe-multiple-cursors-mode))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/mark-previous-like-this-word (arg)
|
||||||
|
"Find and mark the previous part of the buffer matching the currently active region
|
||||||
|
If no region is active, mark the word at the point and find the previous match
|
||||||
|
With negative ARG, delete the last one instead.
|
||||||
|
With zero ARG, skip the last one and mark previous."
|
||||||
|
(interactive "p")
|
||||||
|
(if (< arg 0)
|
||||||
|
(let ((cursor (mc/furthest-cursor-after-point)))
|
||||||
|
(if cursor
|
||||||
|
(mc/remove-fake-cursor cursor)
|
||||||
|
(error "No cursors to be unmarked")))
|
||||||
|
(if (region-active-p)
|
||||||
|
(mc/mark-more-like-this (= arg 0) 'backwards)
|
||||||
|
(mc--select-thing-at-point 'word)
|
||||||
|
(mc/mark-more-like-this (= arg 0) 'backwards)))
|
||||||
|
(mc/maybe-multiple-cursors-mode))
|
||||||
|
|
||||||
|
(defun mc/mark-previous-like-this-symbol (arg)
|
||||||
|
"Find and mark the previous part of the buffer matching the currently active region
|
||||||
|
If no region is active, mark the symbol at the point and find the previous match
|
||||||
|
With negative ARG, delete the last one instead.
|
||||||
|
With zero ARG, skip the last one and mark previous."
|
||||||
|
(interactive "p")
|
||||||
|
(if (< arg 0)
|
||||||
|
(let ((cursor (mc/furthest-cursor-after-point)))
|
||||||
|
(if cursor
|
||||||
|
(mc/remove-fake-cursor cursor)
|
||||||
|
(error "No cursors to be unmarked")))
|
||||||
|
(if (region-active-p)
|
||||||
|
(mc/mark-more-like-this (= arg 0) 'backwards)
|
||||||
|
(mc--select-thing-at-point 'symbol)
|
||||||
|
(mc/mark-more-like-this (= arg 0) 'backwards)))
|
||||||
|
(mc/maybe-multiple-cursors-mode))
|
||||||
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-previous-word-like-this (arg)
|
(defun mc/mark-previous-word-like-this (arg)
|
||||||
|
"Find and mark the previous part of the buffer matching the currently active region
|
||||||
|
The matching region must be a whole word to be a match
|
||||||
|
If no region is active add a cursor on the previous line
|
||||||
|
With negative ARG, delete the last one instead.
|
||||||
|
With zero ARG, skip the last one and mark next."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(let ((mc/enclose-search-term 'words))
|
(let ((mc/enclose-search-term 'words))
|
||||||
(mc/mark-previous-like-this arg)))
|
(mc/mark-previous-like-this arg)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-previous-symbol-like-this (arg)
|
(defun mc/mark-previous-symbol-like-this (arg)
|
||||||
|
"Find and mark the previous part of the buffer matching the currently active region
|
||||||
|
The matching region must be a whole symbol to be a match
|
||||||
|
If no region is active add a cursor on the previous line
|
||||||
|
With negative ARG, delete the last one instead.
|
||||||
|
With zero ARG, skip the last one and mark next."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(let ((mc/enclose-search-term 'symbols))
|
(let ((mc/enclose-search-term 'symbols))
|
||||||
(mc/mark-previous-like-this arg)))
|
(mc/mark-previous-like-this arg)))
|
||||||
|
|
||||||
(defun mc/mark-lines (num-lines direction)
|
(defun mc/mark-lines (num-lines direction)
|
||||||
(dotimes (i num-lines)
|
(dotimes (i (if (= num-lines 0) 1 num-lines))
|
||||||
(mc/create-fake-cursor-at-point)
|
(mc/save-excursion
|
||||||
(ecase direction
|
(let ((furthest-cursor (cl-ecase direction
|
||||||
(forwards (loop do (next-line 1 nil)
|
(forwards (mc/furthest-cursor-after-point))
|
||||||
while (mc/all-fake-cursors (point) (1+ (point)))))
|
(backwards (mc/furthest-cursor-before-point)))))
|
||||||
(backwards (loop do (previous-line 1 nil)
|
(when (overlayp furthest-cursor)
|
||||||
while (mc/all-fake-cursors (point) (1+ (point))))))))
|
(goto-char (overlay-get furthest-cursor 'point))
|
||||||
|
(when (= num-lines 0)
|
||||||
|
(mc/remove-fake-cursor furthest-cursor))))
|
||||||
|
(cl-ecase direction
|
||||||
|
(forwards (next-logical-line 1 nil))
|
||||||
|
(backwards (previous-logical-line 1 nil)))
|
||||||
|
(mc/create-fake-cursor-at-point))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-next-lines (arg)
|
(defun mc/mark-next-lines (arg)
|
||||||
@@ -191,17 +311,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,83 +357,183 @@ 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)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-all-in-region (beg end)
|
(defun mc/mark-all-in-region (beg end &optional search)
|
||||||
"Find and mark all the parts in the region matching the given search"
|
"Find and mark all the parts in the region matching the given search"
|
||||||
(interactive "r")
|
(interactive "r")
|
||||||
(let ((search (read-from-minibuffer "Mark all in region: "))
|
(let ((search (or search (read-from-minibuffer "Mark all in region: ")))
|
||||||
(case-fold-search nil))
|
(case-fold-search nil))
|
||||||
(mc/remove-fake-cursors)
|
(if (string= search "")
|
||||||
(goto-char beg)
|
(message "Mark aborted")
|
||||||
(while (search-forward search end t)
|
(progn
|
||||||
(push-mark (match-beginning 0))
|
(mc/remove-fake-cursors)
|
||||||
(mc/create-fake-cursor-at-point))
|
(goto-char beg)
|
||||||
(let ((first (mc/furthest-cursor-before-point)))
|
(while (search-forward search end t)
|
||||||
(if (not first)
|
(push-mark (match-beginning 0))
|
||||||
(error "Search failed for %S" search)
|
(mc/create-fake-cursor-at-point))
|
||||||
(mc/pop-state-from-overlay first))))
|
(let ((first (mc/furthest-cursor-before-point)))
|
||||||
(if (> (mc/num-cursors) 1)
|
(if (not first)
|
||||||
(multiple-cursors-mode 1)
|
(error "Search failed for %S" search)
|
||||||
(multiple-cursors-mode 0)))
|
(mc/pop-state-from-overlay first)))
|
||||||
|
(if (> (mc/num-cursors) 1)
|
||||||
|
(multiple-cursors-mode 1)
|
||||||
|
(multiple-cursors-mode 0))))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/mark-all-in-region-regexp (beg end)
|
||||||
|
"Find and mark all the parts in the region matching the given regexp."
|
||||||
|
(interactive "r")
|
||||||
|
(let ((search (read-regexp "Mark regexp in region: "))
|
||||||
|
(case-fold-search nil))
|
||||||
|
(if (string= search "")
|
||||||
|
(message "Mark aborted")
|
||||||
|
(progn
|
||||||
|
(mc/remove-fake-cursors)
|
||||||
|
(goto-char beg)
|
||||||
|
(let ((lastmatch))
|
||||||
|
(while (and (< (point) end) ; can happen because of (forward-char)
|
||||||
|
(search-forward-regexp search end t))
|
||||||
|
(push-mark (match-beginning 0))
|
||||||
|
(mc/create-fake-cursor-at-point)
|
||||||
|
(setq lastmatch (point))
|
||||||
|
(when (= (point) (match-beginning 0))
|
||||||
|
(forward-char)))
|
||||||
|
(unless lastmatch
|
||||||
|
(error "Search failed for %S" search)))
|
||||||
|
(goto-char (match-end 0))
|
||||||
|
(if (< (mc/num-cursors) 3)
|
||||||
|
(multiple-cursors-mode 0)
|
||||||
|
(mc/pop-state-from-overlay (mc/furthest-cursor-before-point))
|
||||||
|
(multiple-cursors-mode 1))))))
|
||||||
|
|
||||||
|
(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 +546,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 +566,27 @@ 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 ()
|
;;;###autoload
|
||||||
(and (not (use-region-p))
|
(defun mc/mark-all-dwim (arg)
|
||||||
(derived-mode-p 'sgml-mode)))
|
"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 ()
|
(defun mc--in-defun ()
|
||||||
(bounds-of-thing-at-point 'defun))
|
(bounds-of-thing-at-point 'defun))
|
||||||
@@ -355,6 +606,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 +618,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 +651,32 @@ With prefix, it behaves the same as original `mc/mark-all-like-this'"
|
|||||||
(>= (point) beg)
|
(>= (point) beg)
|
||||||
(<= (point) end))))
|
(<= (point) end))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/toggle-cursor-on-click (event)
|
||||||
|
"Add a cursor where you click, or remove a fake cursor that is
|
||||||
|
already there."
|
||||||
|
(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))
|
||||||
|
(let ((pt (posn-point position)))
|
||||||
|
(if (numberp pt)
|
||||||
|
;; is there a fake cursor with the actual *point* right where we are?
|
||||||
|
(let ((existing (mc/fake-cursor-at-point pt)))
|
||||||
|
(if existing
|
||||||
|
(mc/remove-fake-cursor existing)
|
||||||
|
(save-excursion
|
||||||
|
(goto-char pt)
|
||||||
|
(mc/create-fake-cursor-at-point))))))
|
||||||
|
(mc/maybe-multiple-cursors-mode)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defalias 'mc/add-cursor-on-click 'mc/toggle-cursor-on-click)
|
||||||
|
|
||||||
;;;###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."
|
||||||
@@ -425,6 +704,30 @@ With prefix, it behaves the same as original `mc/mark-all-like-this'"
|
|||||||
(save-excursion
|
(save-excursion
|
||||||
(not (null (sgml-get-context)))))
|
(not (null (sgml-get-context)))))
|
||||||
|
|
||||||
|
(defun mc/split-region (beg end search)
|
||||||
|
"Split region each time SEARCH occurs in the buffer.
|
||||||
|
|
||||||
|
This can be thought of as an inverse to `mc/mark-all-in-region'."
|
||||||
|
(interactive "r\nsSplit on: ")
|
||||||
|
(let ((case-fold-search nil))
|
||||||
|
(if (string= search "")
|
||||||
|
(user-error "Empty search term")
|
||||||
|
(progn
|
||||||
|
(mc/remove-fake-cursors)
|
||||||
|
(goto-char beg)
|
||||||
|
(push-mark beg)
|
||||||
|
(while (search-forward search end t)
|
||||||
|
(save-excursion
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
(mc/create-fake-cursor-at-point))
|
||||||
|
(push-mark (match-end 0)))
|
||||||
|
(unless (= (point) end)
|
||||||
|
(goto-char end))
|
||||||
|
(mc/create-fake-cursor-at-point)
|
||||||
|
(if (> (mc/num-cursors) 1)
|
||||||
|
(multiple-cursors-mode 1)
|
||||||
|
(multiple-cursors-mode 0))))))
|
||||||
|
|
||||||
(provide 'mc-mark-more)
|
(provide 'mc-mark-more)
|
||||||
|
|
||||||
;;; mc-mark-more.el ends here
|
;;; mc-mark-more.el ends here
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -0,0 +1,150 @@
|
|||||||
|
;;; mc-separate-operations.el - functions that work differently on each cursor
|
||||||
|
|
||||||
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
|
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||||
|
;; Keywords: editing cursors
|
||||||
|
|
||||||
|
;; 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 of the License, 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; This file contains functions that work differently on each cursor,
|
||||||
|
;; instead of treating all of them the same.
|
||||||
|
|
||||||
|
;; Please see multiple-cursors.el for more commentary.
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(require 'multiple-cursors-core)
|
||||||
|
|
||||||
|
(defcustom mc/insert-numbers-default 0
|
||||||
|
"The default number at which to start counting for
|
||||||
|
`mc/insert-numbers'"
|
||||||
|
:type 'integer
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
|
(defvar mc--insert-numbers-number 0)
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/insert-numbers (arg)
|
||||||
|
"Insert increasing numbers for each cursor, starting at
|
||||||
|
`mc/insert-numbers-default' or ARG."
|
||||||
|
(interactive "P")
|
||||||
|
(setq mc--insert-numbers-number (or (and arg (prefix-numeric-value arg))
|
||||||
|
mc/insert-numbers-default))
|
||||||
|
(mc/for-each-cursor-ordered
|
||||||
|
(mc/execute-command-for-fake-cursor 'mc--insert-number-and-increase cursor)))
|
||||||
|
|
||||||
|
(defun mc--insert-number-and-increase ()
|
||||||
|
(interactive)
|
||||||
|
(insert (number-to-string mc--insert-numbers-number))
|
||||||
|
(setq mc--insert-numbers-number (1+ mc--insert-numbers-number)))
|
||||||
|
|
||||||
|
(defun mc--ordered-region-strings ()
|
||||||
|
(let (strings)
|
||||||
|
(save-excursion
|
||||||
|
(mc/for-each-cursor-ordered
|
||||||
|
(setq strings (cons (buffer-substring-no-properties
|
||||||
|
(mc/cursor-beg cursor)
|
||||||
|
(mc/cursor-end cursor)) strings))))
|
||||||
|
(nreverse strings)))
|
||||||
|
|
||||||
|
(defvar mc--insert-letters-number 0)
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/insert-letters (arg)
|
||||||
|
"Insert increasing letters for each cursor, starting at 0 or ARG.
|
||||||
|
Where letter[0]=a letter[2]=c letter[26]=aa"
|
||||||
|
(interactive "P")
|
||||||
|
(setq mc--insert-letters-number (or (and arg (prefix-numeric-value arg))
|
||||||
|
0))
|
||||||
|
(mc/for-each-cursor-ordered
|
||||||
|
(mc/execute-command-for-fake-cursor 'mc--insert-letter-and-increase cursor)))
|
||||||
|
|
||||||
|
(defun mc--number-to-letters (number)
|
||||||
|
(let ((letter
|
||||||
|
(char-to-string
|
||||||
|
(+ (mod number 26) ?a)))
|
||||||
|
(number2 (/ number 26)))
|
||||||
|
(if (> number2 0)
|
||||||
|
(concat (mc--number-to-letters (- number2 1)) letter)
|
||||||
|
letter)))
|
||||||
|
|
||||||
|
(defun mc--insert-letter-and-increase ()
|
||||||
|
(interactive)
|
||||||
|
(insert (mc--number-to-letters mc--insert-letters-number))
|
||||||
|
(setq mc--insert-letters-number (1+ mc--insert-letters-number)))
|
||||||
|
|
||||||
|
(defvar mc--strings-to-replace nil)
|
||||||
|
|
||||||
|
(defun mc--replace-region-strings-1 ()
|
||||||
|
(interactive)
|
||||||
|
(delete-region (region-beginning) (region-end))
|
||||||
|
(save-excursion (insert (car mc--strings-to-replace)))
|
||||||
|
(setq mc--strings-to-replace (cdr mc--strings-to-replace)))
|
||||||
|
|
||||||
|
(defun mc--replace-region-strings ()
|
||||||
|
(mc/for-each-cursor-ordered
|
||||||
|
(mc/execute-command-for-fake-cursor 'mc--replace-region-strings-1 cursor)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/reverse-regions ()
|
||||||
|
(interactive)
|
||||||
|
(if (not multiple-cursors-mode)
|
||||||
|
(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)))
|
||||||
|
(mc--replace-region-strings)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/sort-regions ()
|
||||||
|
(interactive)
|
||||||
|
(unless (use-region-p)
|
||||||
|
(mc/execute-command-for-all-cursors 'mark-sexp))
|
||||||
|
(setq mc--strings-to-replace (sort (mc--ordered-region-strings) 'string<))
|
||||||
|
(mc--replace-region-strings))
|
||||||
|
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/vertical-align (character)
|
||||||
|
"Aligns all cursors vertically with a given CHARACTER to the one with the
|
||||||
|
highest colum number (the rightest).
|
||||||
|
Might not behave as intended if more than one cursors are on the same line."
|
||||||
|
(interactive "c")
|
||||||
|
(let ((rightest-column (current-column)))
|
||||||
|
(mc/execute-command-for-all-cursors
|
||||||
|
(lambda () "get the rightest cursor"
|
||||||
|
(interactive)
|
||||||
|
(setq rightest-column (max (current-column) rightest-column))
|
||||||
|
))
|
||||||
|
(mc/execute-command-for-all-cursors
|
||||||
|
(lambda ()
|
||||||
|
(interactive)
|
||||||
|
(let ((missing-spaces (- rightest-column (current-column))))
|
||||||
|
(save-excursion (insert (make-string missing-spaces character)))
|
||||||
|
(forward-char missing-spaces))))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/vertical-align-with-space ()
|
||||||
|
"Aligns all cursors with whitespace like `mc/vertical-align' does"
|
||||||
|
(interactive)
|
||||||
|
(mc/vertical-align 32))
|
||||||
|
|
||||||
|
(provide 'mc-separate-operations)
|
||||||
|
;;; mc-separate-operations.el ends here
|
||||||
+220
-89
@@ -1,6 +1,6 @@
|
|||||||
;;; multiple-cursors-core.el --- An experiment in multiple cursors for emacs.
|
;;; multiple-cursors-core.el --- An experiment in multiple cursors for emacs.
|
||||||
|
|
||||||
;; Copyright (C) 2012 Magnar Sveen
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||||
;; Keywords: editing cursors
|
;; Keywords: editing cursors
|
||||||
@@ -25,15 +25,21 @@
|
|||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
(require 'cl)
|
(require 'cl-lib)
|
||||||
|
|
||||||
(require 'rect)
|
(require 'rect)
|
||||||
|
|
||||||
|
(defvar mc--read-char)
|
||||||
|
|
||||||
(defface mc/cursor-face
|
(defface mc/cursor-face
|
||||||
'((t (:inverse-video t)))
|
'((t (:inverse-video t)))
|
||||||
"The face used for fake cursors"
|
"The face used for fake cursors"
|
||||||
:group 'multiple-cursors)
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
|
(defface mc/cursor-bar-face
|
||||||
|
`((t (:height 1 :background ,(face-attribute 'cursor :background))))
|
||||||
|
"The face used for fake cursors if the cursor-type is bar"
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
(defface mc/region-face
|
(defface mc/region-face
|
||||||
'((t :inherit region))
|
'((t :inherit region))
|
||||||
"The face used for fake regions"
|
"The face used for fake regions"
|
||||||
@@ -41,18 +47,19 @@
|
|||||||
|
|
||||||
(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)))))
|
||||||
,@forms
|
(setq buffer-undo-list (cons ,uc buffer-undo-list))
|
||||||
(if (eq undo-cleaner (car buffer-undo-list)) ;; if nothing has been added to the undo-list
|
,@forms
|
||||||
(setq buffer-undo-list (cdr buffer-undo-list)) ;; then pop the cleaner right off again
|
(if (eq ,uc (car buffer-undo-list)) ;; if nothing has been added to the undo-list
|
||||||
(setq buffer-undo-list ;; otherwise add a function to activate this cursor
|
(setq buffer-undo-list (cdr buffer-undo-list)) ;; then pop the cleaner right off again
|
||||||
(cons (cons 'apply (cons 'activate-cursor-for-undo (list id))) buffer-undo-list)))))
|
(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)
|
(defun mc/all-fake-cursors (&optional start end)
|
||||||
(remove-if-not 'mc/fake-cursor-p
|
(cl-remove-if-not 'mc/fake-cursor-p
|
||||||
(overlays-in (or start (point-min))
|
(overlays-in (or start (point-min))
|
||||||
(or end (point-max)))))
|
(or end (point-max)))))
|
||||||
|
|
||||||
(defmacro mc/for-each-fake-cursor (&rest forms)
|
(defmacro mc/for-each-fake-cursor (&rest forms)
|
||||||
"Runs the body for each fake cursor, bound to the name cursor"
|
"Runs the body for each fake cursor, bound to the name cursor"
|
||||||
@@ -61,46 +68,61 @@
|
|||||||
|
|
||||||
(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")))
|
||||||
(make-overlay (point) (point) nil nil t))))
|
`(let ((,cs (mc/store-current-state-in-overlay
|
||||||
(overlay-put current-state 'type 'original-cursor)
|
(make-overlay (point) (point) nil nil t))))
|
||||||
(save-excursion ,@forms)
|
(overlay-put ,cs 'type 'original-cursor)
|
||||||
(mc/pop-state-from-overlay current-state)))
|
(save-excursion ,@forms)
|
||||||
|
(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 (mc/create-fake-cursor-at-point)))
|
(let ((rci (make-symbol "real-cursor-id")))
|
||||||
(mapc #'(lambda (cursor)
|
`(let ((,rci (overlay-get (mc/create-fake-cursor-at-point) 'mc-id)))
|
||||||
(when (mc/fake-cursor-p cursor)
|
(mapc #'(lambda (cursor)
|
||||||
,@forms))
|
(when (mc/fake-cursor-p cursor)
|
||||||
(sort (overlays-in (point-min) (point-max)) 'mc--compare-by-overlay-start))
|
,@forms))
|
||||||
(mc/pop-state-from-overlay real-cursor)))
|
(sort (overlays-in (point-min) (point-max)) 'mc--compare-by-overlay-start))
|
||||||
|
(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")))
|
||||||
,@forms
|
`(let ((,p (set-marker (make-marker) (point)))
|
||||||
(goto-char p)
|
(,s (set-marker (make-marker) (window-start)))
|
||||||
(set-window-start nil start)
|
(,h (window-hscroll)))
|
||||||
(set-window-hscroll nil hscroll)
|
,@forms
|
||||||
(set-marker p nil)
|
(goto-char ,p)
|
||||||
(set-marker start nil)))
|
(set-window-start nil ,s t)
|
||||||
|
(set-window-hscroll nil ,h)
|
||||||
|
(set-marker ,p nil)
|
||||||
|
(set-marker ,s nil))))
|
||||||
|
|
||||||
|
(defun mc/cursor-is-bar ()
|
||||||
|
"Return non-nil if the cursor is a bar."
|
||||||
|
(or (eq cursor-type 'bar)
|
||||||
|
(and (listp cursor-type)
|
||||||
|
(eq (car cursor-type) 'bar))))
|
||||||
|
|
||||||
(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."
|
||||||
(let ((overlay (make-overlay pos pos nil nil nil)))
|
(let ((overlay (make-overlay pos pos nil nil nil)))
|
||||||
(overlay-put overlay 'after-string (propertize " " 'face 'mc/cursor-face))
|
(if (mc/cursor-is-bar)
|
||||||
|
(overlay-put overlay 'before-string (propertize "|" 'face 'mc/cursor-bar-face))
|
||||||
|
(overlay-put overlay 'after-string (propertize " " 'face 'mc/cursor-face)))
|
||||||
overlay))
|
overlay))
|
||||||
|
|
||||||
(defun mc/make-cursor-overlay-inline (pos)
|
(defun mc/make-cursor-overlay-inline (pos)
|
||||||
"Create overlay to look like cursor inside text."
|
"Create overlay to look like cursor inside text."
|
||||||
(let ((overlay (make-overlay pos (1+ pos) nil nil nil)))
|
(let ((overlay (make-overlay pos (1+ pos) nil nil nil)))
|
||||||
(overlay-put overlay 'face 'mc/cursor-face)
|
(if (mc/cursor-is-bar)
|
||||||
|
(overlay-put overlay 'before-string (propertize "|" 'face 'mc/cursor-bar-face))
|
||||||
|
(overlay-put overlay 'face 'mc/cursor-face))
|
||||||
overlay))
|
overlay))
|
||||||
|
|
||||||
(defun mc/make-cursor-overlay-at-point ()
|
(defun mc/make-cursor-overlay-at-point ()
|
||||||
@@ -118,21 +140,24 @@ 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
|
||||||
|
autopair-action
|
||||||
autopair-wrap-action
|
autopair-wrap-action
|
||||||
|
temporary-goal-column
|
||||||
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 'mark (set-marker (make-marker)
|
||||||
(overlay-put o 'kill-ring-yank-pointer kill-ring-yank-pointer)
|
(let ((mark-even-if-inactive t))
|
||||||
(overlay-put o 'mark (set-marker (make-marker) (mark)))
|
(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)
|
||||||
@@ -140,13 +165,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)))))
|
||||||
|
|
||||||
@@ -172,11 +191,39 @@ highlights the entire width of the window."
|
|||||||
|
|
||||||
(defun mc/create-cursor-id ()
|
(defun mc/create-cursor-id ()
|
||||||
"Returns a unique cursor id"
|
"Returns a unique cursor id"
|
||||||
(incf mc--current-cursor-id))
|
(cl-incf mc--current-cursor-id))
|
||||||
|
|
||||||
|
(defvar mc--max-cursors-original nil
|
||||||
|
"This variable maintains the original maximum number of cursors.
|
||||||
|
When `mc/create-fake-cursor-at-point' is called and
|
||||||
|
`mc/max-cursors' is overridden, this value serves as a backup so
|
||||||
|
that `mc/max-cursors' can take on a new value. When
|
||||||
|
`mc/remove-fake-cursors' is called, the values are reset.")
|
||||||
|
|
||||||
|
(defcustom mc/max-cursors nil
|
||||||
|
"Safety ceiling for the number of active cursors.
|
||||||
|
If your emacs slows down or freezes when using too many cursors,
|
||||||
|
customize this value appropriately.
|
||||||
|
|
||||||
|
Cursors will be added until this value is reached, at which point
|
||||||
|
you can either temporarily override the value or abort the
|
||||||
|
operation entirely.
|
||||||
|
|
||||||
|
If this value is nil, there is no ceiling."
|
||||||
|
:type '(integer)
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
(defun mc/create-fake-cursor-at-point (&optional id)
|
(defun mc/create-fake-cursor-at-point (&optional id)
|
||||||
"Add a fake cursor and possibly a fake active region overlay based on point and mark.
|
"Add a fake cursor and possibly a fake active region overlay based on point and mark.
|
||||||
Saves the current state in the overlay to be restored later."
|
Saves the current state in the overlay to be restored later."
|
||||||
|
(unless mc--max-cursors-original
|
||||||
|
(setq mc--max-cursors-original mc/max-cursors))
|
||||||
|
(when mc/max-cursors
|
||||||
|
(unless (< (mc/num-cursors) mc/max-cursors)
|
||||||
|
(if (yes-or-no-p (format "%d active cursors. Continue? " (mc/num-cursors)))
|
||||||
|
(setq mc/max-cursors (read-number "Enter a new, temporary maximum: "))
|
||||||
|
(mc/remove-fake-cursors)
|
||||||
|
(error "Aborted: too many cursors"))))
|
||||||
(let ((overlay (mc/make-cursor-overlay-at-point)))
|
(let ((overlay (mc/make-cursor-overlay-at-point)))
|
||||||
(overlay-put overlay 'mc-id (or id (mc/create-cursor-id)))
|
(overlay-put overlay 'mc-id (or id (mc/create-cursor-id)))
|
||||||
(overlay-put overlay 'type 'fake-cursor)
|
(overlay-put overlay 'type 'fake-cursor)
|
||||||
@@ -198,6 +245,17 @@ Saves the current state in the overlay to be restored later."
|
|||||||
|
|
||||||
(defvar mc--executing-command-for-fake-cursor nil)
|
(defvar mc--executing-command-for-fake-cursor nil)
|
||||||
|
|
||||||
|
(defun mc/execute-command-for-fake-cursor (cmd cursor)
|
||||||
|
(let ((mc--executing-command-for-fake-cursor t)
|
||||||
|
(id (overlay-get cursor 'mc-id))
|
||||||
|
(annoying-arrows-mode nil)
|
||||||
|
(smooth-scroll-margin 0))
|
||||||
|
(mc/add-fake-cursor-to-undo-list
|
||||||
|
(mc/pop-state-from-overlay cursor)
|
||||||
|
(ignore-errors
|
||||||
|
(mc/execute-command cmd)
|
||||||
|
(mc/create-fake-cursor-at-point id)))))
|
||||||
|
|
||||||
(defun mc/execute-command-for-all-fake-cursors (cmd)
|
(defun mc/execute-command-for-all-fake-cursors (cmd)
|
||||||
"Calls CMD interactively for each cursor.
|
"Calls CMD interactively for each cursor.
|
||||||
It works by moving point to the fake cursor, setting
|
It works by moving point to the fake cursor, setting
|
||||||
@@ -208,20 +266,19 @@ cursor with updated info."
|
|||||||
(mc/save-window-scroll
|
(mc/save-window-scroll
|
||||||
(mc/for-each-fake-cursor
|
(mc/for-each-fake-cursor
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(let ((mc--executing-command-for-fake-cursor t)
|
(mc/execute-command-for-fake-cursor cmd cursor)))))
|
||||||
(id (overlay-get cursor 'mc-id))
|
|
||||||
(annoying-arrows-mode nil)
|
|
||||||
(smooth-scroll-margin 0))
|
|
||||||
(mc/add-fake-cursor-to-undo-list
|
|
||||||
(mc/pop-state-from-overlay cursor)
|
|
||||||
(ignore-errors
|
|
||||||
(mc/execute-command cmd)
|
|
||||||
(mc/create-fake-cursor-at-point id))))))))
|
|
||||||
(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
|
||||||
|
|
||||||
|
(defvar mc--read-char nil)
|
||||||
|
(defvar multiple-cursors-mode nil)
|
||||||
(defadvice read-char (around mc-support activate)
|
(defadvice read-char (around mc-support activate)
|
||||||
(if (not multiple-cursors-mode)
|
(if (not multiple-cursors-mode)
|
||||||
ad-do-it
|
ad-do-it
|
||||||
@@ -229,6 +286,7 @@ cursor with updated info."
|
|||||||
(setq mc--read-char ad-do-it))
|
(setq mc--read-char ad-do-it))
|
||||||
(setq ad-return-value mc--read-char)))
|
(setq ad-return-value mc--read-char)))
|
||||||
|
|
||||||
|
(defvar mc--read-quoted-char nil)
|
||||||
(defadvice read-quoted-char (around mc-support activate)
|
(defadvice read-quoted-char (around mc-support activate)
|
||||||
(if (not multiple-cursors-mode)
|
(if (not multiple-cursors-mode)
|
||||||
ad-do-it
|
ad-do-it
|
||||||
@@ -248,9 +306,9 @@ cursor with updated info."
|
|||||||
|
|
||||||
(defun mc/cursor-with-id (id)
|
(defun mc/cursor-with-id (id)
|
||||||
"Find the first cursor with the given id, or nil"
|
"Find the first cursor with the given id, or nil"
|
||||||
(find-if #'(lambda (o) (and (mc/fake-cursor-p o)
|
(cl-find-if #'(lambda (o) (and (mc/fake-cursor-p o)
|
||||||
(= id (overlay-get o 'mc-id))))
|
(= id (overlay-get o 'mc-id))))
|
||||||
(overlays-in (point-min) (point-max))))
|
(overlays-in (point-min) (point-max))))
|
||||||
|
|
||||||
(defvar mc--stored-state-for-undo nil
|
(defvar mc--stored-state-for-undo nil
|
||||||
"Variable to keep the state of the real cursor while undoing a fake one")
|
"Variable to keep the state of the real cursor while undoing a fake one")
|
||||||
@@ -270,6 +328,16 @@ cursor with updated info."
|
|||||||
(mc/pop-state-from-overlay mc--stored-state-for-undo)
|
(mc/pop-state-from-overlay mc--stored-state-for-undo)
|
||||||
(setq mc--stored-state-for-undo nil)))
|
(setq mc--stored-state-for-undo nil)))
|
||||||
|
|
||||||
|
(defcustom mc/always-run-for-all nil
|
||||||
|
"Disables whitelisting and always executes commands for every fake cursor."
|
||||||
|
:type '(boolean)
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
|
(defcustom mc/always-repeat-command nil
|
||||||
|
"Disables confirmation for `mc/repeat-command' command."
|
||||||
|
:type '(boolean)
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
(defun mc/prompt-for-inclusion-in-whitelist (original-command)
|
(defun mc/prompt-for-inclusion-in-whitelist (original-command)
|
||||||
"Asks the user, then adds the command either to the once-list or the all-list."
|
"Asks the user, then adds the command either to the once-list or the all-list."
|
||||||
(let ((all-p (y-or-n-p (format "Do %S for all cursors?" original-command))))
|
(let ((all-p (y-or-n-p (format "Do %S for all cursors?" original-command))))
|
||||||
@@ -281,8 +349,8 @@ cursor with updated info."
|
|||||||
|
|
||||||
(defun mc/num-cursors ()
|
(defun mc/num-cursors ()
|
||||||
"The number of cursors (real and fake) in the buffer."
|
"The number of cursors (real and fake) in the buffer."
|
||||||
(1+ (count-if 'mc/fake-cursor-p
|
(1+ (cl-count-if 'mc/fake-cursor-p
|
||||||
(overlays-in (point-min) (point-max)))))
|
(overlays-in (point-min) (point-max)))))
|
||||||
|
|
||||||
(defvar mc--this-command nil
|
(defvar mc--this-command nil
|
||||||
"Used to store the original command being run.")
|
"Used to store the original command being run.")
|
||||||
@@ -297,8 +365,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."
|
||||||
@@ -328,7 +398,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)
|
||||||
@@ -340,9 +409,16 @@ the original cursor, to inform about the lack of support."
|
|||||||
|
|
||||||
;; if it's a lambda, we can't know if it's supported or not
|
;; if it's a lambda, we can't know if it's supported or not
|
||||||
;; - so go ahead and assume it's ok, because we're just optimistic like that
|
;; - so go ahead and assume it's ok, because we're just optimistic like that
|
||||||
(if (not (symbolp original-command))
|
(if (or (not (symbolp original-command))
|
||||||
|
;; lambda registered by smartrep
|
||||||
|
(string-prefix-p "(" (symbol-name original-command)))
|
||||||
(mc/execute-command-for-all-fake-cursors original-command)
|
(mc/execute-command-for-all-fake-cursors original-command)
|
||||||
|
|
||||||
|
;; smartrep `intern's commands into own obarray to help
|
||||||
|
;; `describe-bindings'. So, let's re-`intern' here to
|
||||||
|
;; make the command comparable by `eq'.
|
||||||
|
(setq original-command (intern (symbol-name original-command)))
|
||||||
|
|
||||||
;; otherwise it's a symbol, and we can be more thorough
|
;; otherwise it's a symbol, and we can be more thorough
|
||||||
(if (get original-command 'mc--unsupported)
|
(if (get original-command 'mc--unsupported)
|
||||||
(message "%S is not supported with multiple cursors%s"
|
(message "%S is not supported with multiple cursors%s"
|
||||||
@@ -351,7 +427,8 @@ the original cursor, to inform about the lack of support."
|
|||||||
(when (and original-command
|
(when (and original-command
|
||||||
(not (memq original-command mc--default-cmds-to-run-once))
|
(not (memq original-command mc--default-cmds-to-run-once))
|
||||||
(not (memq original-command mc/cmds-to-run-once))
|
(not (memq original-command mc/cmds-to-run-once))
|
||||||
(or (memq original-command mc--default-cmds-to-run-for-all)
|
(or mc/always-run-for-all
|
||||||
|
(memq original-command mc--default-cmds-to-run-for-all)
|
||||||
(memq original-command mc/cmds-to-run-for-all)
|
(memq original-command mc/cmds-to-run-for-all)
|
||||||
(mc/prompt-for-inclusion-in-whitelist original-command)))
|
(mc/prompt-for-inclusion-in-whitelist original-command)))
|
||||||
(mc/execute-command-for-all-fake-cursors original-command))))))))))
|
(mc/execute-command-for-all-fake-cursors original-command))))))))))
|
||||||
@@ -361,7 +438,10 @@ the original cursor, to inform about the lack of support."
|
|||||||
Do not use to conclude editing with multiple cursors. For that
|
Do not use to conclude editing with multiple cursors. For that
|
||||||
you should disable multiple-cursors-mode."
|
you should disable multiple-cursors-mode."
|
||||||
(mc/for-each-fake-cursor
|
(mc/for-each-fake-cursor
|
||||||
(mc/remove-fake-cursor cursor)))
|
(mc/remove-fake-cursor cursor))
|
||||||
|
(when mc--max-cursors-original
|
||||||
|
(setq mc/max-cursors mc--max-cursors-original))
|
||||||
|
(setq mc--max-cursors-original nil))
|
||||||
|
|
||||||
(defun mc/keyboard-quit ()
|
(defun mc/keyboard-quit ()
|
||||||
"Deactivate mark if there are any active, otherwise exit multiple-cursors-mode."
|
"Deactivate mark if there are any active, otherwise exit multiple-cursors-mode."
|
||||||
@@ -370,23 +450,38 @@ you should disable multiple-cursors-mode."
|
|||||||
(multiple-cursors-mode 0)
|
(multiple-cursors-mode 0)
|
||||||
(deactivate-mark)))
|
(deactivate-mark)))
|
||||||
|
|
||||||
|
(defun mc/repeat-command ()
|
||||||
|
"Run last command from `command-history' for every fake cursor."
|
||||||
|
(interactive)
|
||||||
|
(when (or mc/always-repeat-command
|
||||||
|
(y-or-n-p (format "[mc] repeat complex command: %s? " (caar command-history))))
|
||||||
|
(mc/execute-command-for-all-fake-cursors
|
||||||
|
(lambda () (interactive)
|
||||||
|
(cl-letf (((symbol-function 'read-from-minibuffer)
|
||||||
|
(lambda (p &optional i k r h d m) (read i))))
|
||||||
|
(repeat-complex-command 0))))))
|
||||||
|
|
||||||
(defvar mc/keymap nil
|
(defvar mc/keymap nil
|
||||||
"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)
|
||||||
|
(define-key mc/keymap (kbd "C-:") 'mc/repeat-command)
|
||||||
|
(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 ()
|
||||||
@@ -400,11 +495,11 @@ The entries are returned in the order they are found in the buffer."
|
|||||||
(defun mc--maybe-set-killed-rectangle ()
|
(defun mc--maybe-set-killed-rectangle ()
|
||||||
"Add the latest kill-ring entry for each cursor to killed-rectangle.
|
"Add the latest kill-ring entry for each cursor to killed-rectangle.
|
||||||
So you can paste it in later with `yank-rectangle'."
|
So you can paste it in later with `yank-rectangle'."
|
||||||
(let ((entries (mc--kill-ring-entries)))
|
(let ((entries (let (mc/max-cursors) (mc--kill-ring-entries))))
|
||||||
(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 '(company-mode auto-complete-mode flyspell-mode jedi-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.")
|
||||||
|
|
||||||
@@ -435,6 +530,7 @@ They are temporarily disabled when multiple-cursors are active.")
|
|||||||
:group 'multiple-cursors)
|
:group 'multiple-cursors)
|
||||||
(put 'mc/mode-line 'risky-local-variable t)
|
(put 'mc/mode-line 'risky-local-variable t)
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
(define-minor-mode multiple-cursors-mode
|
(define-minor-mode multiple-cursors-mode
|
||||||
"Mode while multiple cursors are active."
|
"Mode while multiple cursors are active."
|
||||||
nil mc/mode-line mc/keymap
|
nil mc/mode-line mc/keymap
|
||||||
@@ -475,7 +571,8 @@ from being executed if in multiple-cursors-mode."
|
|||||||
(unsupported-cmd isearch-backward ". Feel free to add a compatible version.")
|
(unsupported-cmd isearch-backward ". Feel free to add a compatible version.")
|
||||||
|
|
||||||
;; Make sure pastes from other programs are added to all kill-rings when yanking
|
;; Make sure pastes from other programs are added to all kill-rings when yanking
|
||||||
(defadvice current-kill (before interprogram-paste-for-all-cursors activate)
|
(defadvice current-kill (before interprogram-paste-for-all-cursors
|
||||||
|
(n &optional do-not-move) activate)
|
||||||
(let ((interprogram-paste (and (= n 0)
|
(let ((interprogram-paste (and (= n 0)
|
||||||
interprogram-paste-function
|
interprogram-paste-function
|
||||||
(funcall interprogram-paste-function))))
|
(funcall interprogram-paste-function))))
|
||||||
@@ -499,19 +596,21 @@ from being executed if in multiple-cursors-mode."
|
|||||||
(overlay-put cursor 'kill-ring kill-ring)
|
(overlay-put cursor 'kill-ring kill-ring)
|
||||||
(overlay-put cursor 'kill-ring-yank-pointer kill-ring-yank-pointer)))))))
|
(overlay-put cursor 'kill-ring-yank-pointer kill-ring-yank-pointer)))))))
|
||||||
|
|
||||||
(defvar mc/list-file "~/.emacs.d/.mc-lists.el"
|
(defcustom mc/list-file (locate-user-emacs-file ".mc-lists.el")
|
||||||
"The position of the file that keeps track of your preferences
|
"The position of the file that keeps track of your preferences
|
||||||
for running commands with multiple cursors.")
|
for running commands with multiple cursors."
|
||||||
|
:type 'file
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
(defun mc/dump-list (list-symbol)
|
(defun mc/dump-list (list-symbol)
|
||||||
"Insert (setq 'LIST-SYMBOL LIST-VALUE) to current buffer."
|
"Insert (setq 'LIST-SYMBOL LIST-VALUE) to current buffer."
|
||||||
(symbol-macrolet ((value (symbol-value list-symbol)))
|
(cl-symbol-macrolet ((value (symbol-value list-symbol)))
|
||||||
(insert "(setq " (symbol-name list-symbol) "\n"
|
(insert "(setq " (symbol-name list-symbol) "\n"
|
||||||
" '(")
|
" '(")
|
||||||
(newline-and-indent)
|
(newline-and-indent)
|
||||||
(set list-symbol
|
(set list-symbol
|
||||||
(sort value (lambda (x y) (string-lessp (symbol-name x)
|
(sort value (lambda (x y) (string-lessp (symbol-name x)
|
||||||
(symbol-name y)))))
|
(symbol-name y)))))
|
||||||
(mapc #'(lambda (cmd) (insert (format "%S" cmd)) (newline-and-indent))
|
(mapc #'(lambda (cmd) (insert (format "%S" cmd)) (newline-and-indent))
|
||||||
value)
|
value)
|
||||||
(insert "))")
|
(insert "))")
|
||||||
@@ -540,9 +639,13 @@ for running commands with multiple cursors.")
|
|||||||
mc/edit-ends-of-lines
|
mc/edit-ends-of-lines
|
||||||
mc/edit-beginnings-of-lines
|
mc/edit-beginnings-of-lines
|
||||||
mc/mark-next-like-this
|
mc/mark-next-like-this
|
||||||
|
mc/mark-next-like-this-word
|
||||||
|
mc/mark-next-like-this-symbol
|
||||||
mc/mark-next-word-like-this
|
mc/mark-next-word-like-this
|
||||||
mc/mark-next-symbol-like-this
|
mc/mark-next-symbol-like-this
|
||||||
mc/mark-previous-like-this
|
mc/mark-previous-like-this
|
||||||
|
mc/mark-previous-like-this-word
|
||||||
|
mc/mark-previous-like-this-symbol
|
||||||
mc/mark-previous-word-like-this
|
mc/mark-previous-word-like-this
|
||||||
mc/mark-previous-symbol-like-this
|
mc/mark-previous-symbol-like-this
|
||||||
mc/mark-all-like-this
|
mc/mark-all-like-this
|
||||||
@@ -553,15 +656,37 @@ 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-letters
|
||||||
|
mc/sort-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
|
||||||
|
mc-hide-unmatched-lines-mode
|
||||||
|
mc/repeat-command
|
||||||
|
hum/keyboard-quit
|
||||||
|
hum/unhide-invisible-overlays
|
||||||
save-buffer
|
save-buffer
|
||||||
ido-exit-minibuffer
|
ido-exit-minibuffer
|
||||||
|
ivy-done
|
||||||
exit-minibuffer
|
exit-minibuffer
|
||||||
minibuffer-complete-and-exit
|
minibuffer-complete-and-exit
|
||||||
execute-extended-command
|
execute-extended-command
|
||||||
|
eval-expression
|
||||||
undo
|
undo
|
||||||
redo
|
redo
|
||||||
undo-tree-undo
|
undo-tree-undo
|
||||||
@@ -595,7 +720,8 @@ for running commands with multiple cursors.")
|
|||||||
windmove-left
|
windmove-left
|
||||||
windmove-right
|
windmove-right
|
||||||
windmove-up
|
windmove-up
|
||||||
windmove-down))
|
windmove-down
|
||||||
|
repeat-complex-command))
|
||||||
|
|
||||||
(defvar mc--default-cmds-to-run-for-all nil
|
(defvar mc--default-cmds-to-run-for-all nil
|
||||||
"Default set of commands that should be mirrored by all cursors")
|
"Default set of commands that should be mirrored by all cursors")
|
||||||
@@ -641,8 +767,11 @@ 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
|
||||||
|
cperl-electric-backspace
|
||||||
|
python-indent-dedent-line-backspace
|
||||||
paredit-backward-delete
|
paredit-backward-delete
|
||||||
autopair-backspace
|
autopair-backspace
|
||||||
just-one-space
|
just-one-space
|
||||||
@@ -652,6 +781,7 @@ for running commands with multiple cursors.")
|
|||||||
exchange-point-and-mark
|
exchange-point-and-mark
|
||||||
cua-set-mark
|
cua-set-mark
|
||||||
cua-replace-region
|
cua-replace-region
|
||||||
|
cua-delete-region
|
||||||
move-end-of-line
|
move-end-of-line
|
||||||
beginning-of-line
|
beginning-of-line
|
||||||
move-beginning-of-line
|
move-beginning-of-line
|
||||||
@@ -676,13 +806,14 @@ for running commands with multiple cursors.")
|
|||||||
(defvar mc/cmds-to-run-for-all nil
|
(defvar mc/cmds-to-run-for-all nil
|
||||||
"Commands to run for all cursors in multiple-cursors-mode")
|
"Commands to run for all cursors in multiple-cursors-mode")
|
||||||
|
|
||||||
(load mc/list-file t) ;; load, but no errors if it does not exist yet please
|
;; load, but no errors if it does not exist yet please, and no message
|
||||||
|
;; while loading
|
||||||
|
(load mc/list-file 'noerror 'nomessage)
|
||||||
|
|
||||||
(provide 'multiple-cursors-core)
|
(provide 'multiple-cursors-core)
|
||||||
|
|
||||||
;; Local Variables:
|
;; Local Variables:
|
||||||
;; coding: utf-8
|
;; coding: utf-8
|
||||||
;; byte-compile-warnings: (not cl-functions)
|
|
||||||
;; End:
|
;; End:
|
||||||
|
|
||||||
;;; multiple-cursors-core.el ends here
|
;;; multiple-cursors-core.el ends here
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
(define-package "multiple-cursors" "1.1.5"
|
(define-package "multiple-cursors" "1.3.0"
|
||||||
"Multiple cursors for Emacs.")
|
"Multiple cursors for Emacs."
|
||||||
|
'((cl-lib "0.5")))
|
||||||
|
|||||||
+46
-8
@@ -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-2016 Magnar Sveen
|
||||||
|
|
||||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||||
|
;; Version: 1.4.0
|
||||||
;; 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
|
||||||
@@ -60,12 +61,15 @@
|
|||||||
;; ### Mark one more occurrence
|
;; ### Mark one more occurrence
|
||||||
|
|
||||||
;; - `mc/mark-next-like-this`: Adds a cursor and region at the next part of the buffer forwards that matches the current region.
|
;; - `mc/mark-next-like-this`: Adds a cursor and region at the next part of the buffer forwards that matches the current region.
|
||||||
|
;; - `mc/mark-next-like-this-word`: Adds a cursor and region at the next part of the buffer forwards that matches the current region, if no region is selected it selects the word at the point.
|
||||||
|
;; - `mc/mark-next-like-this-symbol`: Adds a cursor and region at the next part of the buffer forwards that matches the current region, if no region is selected it selects the symbol at the point.
|
||||||
;; - `mc/mark-next-word-like-this`: Like `mc/mark-next-like-this` but only for whole words.
|
;; - `mc/mark-next-word-like-this`: Like `mc/mark-next-like-this` but only for whole words.
|
||||||
;; - `mc/mark-next-symbol-like-this`: Like `mc/mark-next-like-this` but only for whole symbols.
|
;; - `mc/mark-next-symbol-like-this`: Like `mc/mark-next-like-this` but only for whole symbols.
|
||||||
;; - `mc/mark-previous-like-this`: Adds a cursor and region at the next part of the buffer backwards that matches the current region.
|
;; - `mc/mark-previous-like-this`: Adds a cursor and region at the next part of the buffer backwards that matches the current region.
|
||||||
;; - `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
|
||||||
|
|
||||||
@@ -82,29 +86,56 @@
|
|||||||
|
|
||||||
;; - `set-rectangular-region-anchor`: Think of this one as `set-mark` except you're marking a rectangular region.
|
;; - `set-rectangular-region-anchor`: Think of this one as `set-mark` except you're marking a rectangular region.
|
||||||
;; - `mc/mark-sgml-tag-pair`: Mark the current opening and closing tag.
|
;; - `mc/mark-sgml-tag-pair`: Mark the current opening and closing tag.
|
||||||
|
;; - `mc/insert-numbers`: Insert increasing numbers for each cursor, top to bottom.
|
||||||
|
;; - `mc/insert-letters`: Insert increasing letters for each cursor, top to bottom.
|
||||||
|
;; - `mc/sort-regions`: Sort the marked regions alphabetically.
|
||||||
|
;; - `mc/reverse-regions`: Reverse the order of the marked regions.
|
||||||
|
|
||||||
;; ## Tips and tricks
|
;; ## Tips and tricks
|
||||||
|
|
||||||
;; - 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-next-like-this-word` or
|
||||||
|
;; `mc/mark-next-like-this-symbol` with no region selected. It will
|
||||||
|
;; mark the symbol and add a cursor at the next occurance
|
||||||
|
;;
|
||||||
;; - 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
|
||||||
|
;; 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.
|
||||||
|
;;
|
||||||
|
;; - 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
|
||||||
@@ -155,10 +186,17 @@
|
|||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
|
(defgroup multiple-cursors nil
|
||||||
|
"Multiple cursors for emacs."
|
||||||
|
:group 'editing)
|
||||||
|
|
||||||
(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-hide-unmatched-lines-mode)
|
||||||
|
|
||||||
(provide 'multiple-cursors)
|
(provide 'multiple-cursors)
|
||||||
|
|
||||||
|
|||||||
+28
-22
@@ -1,6 +1,6 @@
|
|||||||
;;; rectangular-region-mode.el
|
;;; rectangular-region-mode.el
|
||||||
|
|
||||||
;; Copyright (C) 2012 Magnar Sveen
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||||
;; Keywords: editing cursors
|
;; Keywords: editing cursors
|
||||||
@@ -38,6 +38,8 @@
|
|||||||
(define-key rectangular-region-mode-map (kbd "C-g") 'rrm/keyboard-quit)
|
(define-key rectangular-region-mode-map (kbd "C-g") 'rrm/keyboard-quit)
|
||||||
(define-key rectangular-region-mode-map (kbd "<return>") 'rrm/switch-to-multiple-cursors)
|
(define-key rectangular-region-mode-map (kbd "<return>") 'rrm/switch-to-multiple-cursors)
|
||||||
|
|
||||||
|
(defvar rectangular-region-mode nil)
|
||||||
|
|
||||||
(defun rrm/keyboard-quit ()
|
(defun rrm/keyboard-quit ()
|
||||||
"Exit rectangular-region-mode."
|
"Exit rectangular-region-mode."
|
||||||
(interactive)
|
(interactive)
|
||||||
@@ -67,27 +69,30 @@ 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."
|
||||||
(rrm/remove-rectangular-region-overlays)
|
(if (not rectangular-region-mode)
|
||||||
(let* ((annoying-arrows-mode nil)
|
(remove-hook 'post-command-hook 'rrm/repaint t)
|
||||||
(point-column (current-column))
|
;; else
|
||||||
(point-line (line-number-at-pos))
|
(rrm/remove-rectangular-region-overlays)
|
||||||
(anchor-column (save-excursion (goto-char rrm/anchor) (current-column)))
|
(let* ((annoying-arrows-mode nil)
|
||||||
(anchor-line (save-excursion (goto-char rrm/anchor) (line-number-at-pos)))
|
(point-column (current-column))
|
||||||
(left-column (if (< point-column anchor-column) point-column anchor-column))
|
(point-line (line-number-at-pos))
|
||||||
(right-column (if (> point-column anchor-column) point-column anchor-column))
|
(anchor-column (save-excursion (goto-char rrm/anchor) (current-column)))
|
||||||
(navigation-step (if (< point-line anchor-line) 1 -1)))
|
(anchor-line (save-excursion (goto-char rrm/anchor) (line-number-at-pos)))
|
||||||
(move-to-column anchor-column)
|
(left-column (if (< point-column anchor-column) point-column anchor-column))
|
||||||
(set-mark (point))
|
(right-column (if (> point-column anchor-column) point-column anchor-column))
|
||||||
(move-to-column point-column)
|
(navigation-step (if (< point-line anchor-line) 1 -1)))
|
||||||
(mc/save-excursion
|
(move-to-column anchor-column)
|
||||||
(while (not (= anchor-line (line-number-at-pos)))
|
(set-mark (point))
|
||||||
(forward-line navigation-step)
|
(move-to-column point-column)
|
||||||
(move-to-column anchor-column)
|
(mc/save-excursion
|
||||||
(when (= anchor-column (current-column))
|
(while (not (= anchor-line (line-number-at-pos)))
|
||||||
(set-mark (point))
|
(forward-line navigation-step)
|
||||||
(move-to-column point-column)
|
(move-to-column anchor-column)
|
||||||
(when (= point-column (current-column))
|
(when (= anchor-column (current-column))
|
||||||
(mc/create-fake-cursor-at-point)))))))
|
(set-mark (point))
|
||||||
|
(move-to-column point-column)
|
||||||
|
(when (= point-column (current-column))
|
||||||
|
(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."
|
||||||
@@ -103,6 +108,7 @@ an exceedingly quick way of adding multiple cursors to multiple lines."
|
|||||||
(when rectangular-region-mode
|
(when rectangular-region-mode
|
||||||
(rrm/switch-to-multiple-cursors)))
|
(rrm/switch-to-multiple-cursors)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
(define-minor-mode rectangular-region-mode
|
(define-minor-mode rectangular-region-mode
|
||||||
"A mode for creating a rectangular region to edit"
|
"A mode for creating a rectangular region to edit"
|
||||||
nil " rr" rectangular-region-mode-map
|
nil " rr" rectangular-region-mode-map
|
||||||
|
|||||||
Executable
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/sh -e
|
||||||
|
cask exec ecukes "$@" --no-win
|
||||||
+3
-2
@@ -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
|
||||||
|
|||||||
-1
Submodule util/ecukes deleted from b2c449cf01
-2544
File diff suppressed because it is too large
Load Diff
-1
Submodule util/espuds deleted from 62ef75cb51
Vendored
-329
@@ -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
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user