mirror of
https://github.com/magnars/multiple-cursors.el.git
synced 2025-10-13 21:03:05 +00:00
Compare commits
330 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
9017f3be6b | ||
![]() |
89f1a8df9b | ||
![]() |
758223c45b | ||
![]() |
bb07ffee68 | ||
![]() |
dd10cf2334 | ||
![]() |
3317246070 | ||
![]() |
46635e7f69 | ||
![]() |
e315120117 | ||
![]() |
c870c18462 | ||
![]() |
ba7852f192 | ||
![]() |
d36c62aa71 | ||
![]() |
5ab154b09e | ||
![]() |
25b0dca82e | ||
![]() |
234806c832 | ||
![]() |
25b98b940c | ||
![]() |
6956e8e12e | ||
![]() |
16223efc2d | ||
![]() |
7f255ce696 | ||
![]() |
351eb6cbb5 | ||
![]() |
558198239e | ||
![]() |
817a7a8d25 | ||
![]() |
c9ea562bd5 | ||
![]() |
72de6a4ec4 | ||
![]() |
03bc44e093 | ||
![]() |
fe0d516745 | ||
![]() |
1e4842d129 | ||
![]() |
225fc0e889 | ||
![]() |
fd8441bfc8 | ||
![]() |
2f003612b7 | ||
![]() |
aae47aebc0 | ||
![]() |
8a60fc7ef0 | ||
![]() |
b139bb6b30 | ||
![]() |
4975afedb3 | ||
![]() |
588daf8c52 | ||
![]() |
616fbdd369 | ||
![]() |
7b13b03c99 | ||
![]() |
cb93501ec7 | ||
![]() |
a9d7764f80 | ||
![]() |
83abb0533a | ||
![]() |
7763f4f9d7 | ||
![]() |
6a04a147ce | ||
![]() |
b880554d04 | ||
![]() |
b9b851a767 | ||
![]() |
b39e9631d6 | ||
![]() |
5ffb19af48 | ||
![]() |
a730c414b1 | ||
![]() |
fc6a6a7462 | ||
![]() |
d27870dff3 | ||
![]() |
5ff2071fac | ||
![]() |
9980faa21f | ||
![]() |
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 | ||
![]() |
424e0667a4 | ||
![]() |
f1a5a39b48 | ||
![]() |
84ab4ee26a | ||
![]() |
07b88080b1 | ||
![]() |
e7605bbd7c | ||
![]() |
dc0aa99459 | ||
![]() |
6339657440 | ||
![]() |
94164f706a | ||
![]() |
52300ff852 | ||
![]() |
129ea778cc | ||
![]() |
0b9aae12ca | ||
![]() |
fa753aa587 | ||
![]() |
bc8af45bfe | ||
![]() |
b218a13cf7 | ||
![]() |
0a081a7c5f | ||
![]() |
839c6ef077 | ||
![]() |
7d79b983ea | ||
![]() |
717c97e32b | ||
![]() |
c010afbbef | ||
![]() |
f721308591 | ||
![]() |
1074c88c99 | ||
![]() |
a37e02b907 | ||
![]() |
fe211c018c | ||
![]() |
1afbb9317c | ||
![]() |
dce6c00fab | ||
![]() |
5f7c92bb74 | ||
![]() |
6b09b9c73f | ||
![]() |
b3ca408f52 | ||
![]() |
7382b462b2 | ||
![]() |
be4067da45 | ||
![]() |
65d4f873fe | ||
![]() |
dce196ce9f | ||
![]() |
bb546b11d8 | ||
![]() |
796fb640e1 | ||
![]() |
c3b2d8483b | ||
![]() |
2818d9e7ef | ||
![]() |
1ec78e195f | ||
![]() |
038c9a7f03 | ||
![]() |
19b1a83925 | ||
![]() |
a8b632386d | ||
![]() |
e4adefc04e | ||
![]() |
324d9354b5 | ||
![]() |
80ebdbb35b | ||
![]() |
9ac7675c78 | ||
![]() |
3f20fc15a7 | ||
![]() |
876937bfa3 | ||
![]() |
fcbb7a4df9 | ||
![]() |
a0f771f3e4 | ||
![]() |
879ddb0e97 | ||
![]() |
6e9ea1ae52 | ||
![]() |
8a12e97b7d | ||
![]() |
f4d5aea860 | ||
![]() |
00f905549e | ||
![]() |
7a6eb0df90 | ||
![]() |
6d4979db46 | ||
![]() |
f040a33e3c | ||
![]() |
64ffd81491 | ||
![]() |
97da9778fd | ||
![]() |
ae0033fe3d | ||
![]() |
5fcc69cc54 |
36
.github/workflows/ci.yml
vendored
Normal file
36
.github/workflows/ci.yml
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
emacs_version:
|
||||
- 25.1
|
||||
- 25.2
|
||||
- 25.3
|
||||
- 26.1
|
||||
- 26.2
|
||||
- 26.3
|
||||
- 27.2
|
||||
- 28.1
|
||||
- snapshot
|
||||
steps:
|
||||
- uses: purcell/setup-emacs@master
|
||||
with:
|
||||
version: ${{ matrix.emacs_version }}
|
||||
- name: Install Cask
|
||||
run: git clone https://github.com/cask/cask ~/.cask
|
||||
- name: Add Cask to PATH
|
||||
run: echo "$HOME/.cask/bin" >> $GITHUB_PATH
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install dependencies with Cask
|
||||
run: cask
|
||||
- name: Run tests
|
||||
run: script -e -c /bin/bash -c 'TERM=xterm ./run-tests.sh'
|
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
elpa
|
||||
*.elc
|
||||
/.ecukes-failing-scenarios
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -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
|
12
.travis.yml
12
.travis.yml
@ -1,12 +0,0 @@
|
||||
language: emacs-lisp
|
||||
before_install:
|
||||
- if [ "$ECUKES_EMACS" = 'emacs-snapshot' ]; then
|
||||
sudo add-apt-repository -y ppa:cassou/emacs &&
|
||||
sudo apt-get update -qq &&
|
||||
sudo apt-get install -qq
|
||||
emacs-snapshot-el emacs-snapshot-gtk emacs-snapshot;
|
||||
fi
|
||||
env:
|
||||
- ECUKES_EMACS=emacs
|
||||
script:
|
||||
./run-travis-ci.sh
|
9
Cask
Normal file
9
Cask
Normal file
@ -0,0 +1,9 @@
|
||||
(source gnu)
|
||||
(source melpa)
|
||||
|
||||
(package-file "multiple-cursors.el")
|
||||
|
||||
(development
|
||||
(depends-on "ecukes")
|
||||
(depends-on "espuds")
|
||||
(depends-on "wrap-region"))
|
198
README.md
198
README.md
@ -1,9 +1,45 @@
|
||||
# multiple-cursors.el [](http://travis-ci.org/magnars/multiple-cursors.el)
|
||||
[](https://github.com/magnars/multiple-cursors.el/actions)
|
||||
[](https://melpa.org/#/multiple-cursors)
|
||||
[](https://stable.melpa.org/#/multiple-cursors)
|
||||
[](https://elpa.nongnu.org/nongnu/multiple-cursors.html)
|
||||
|
||||
# multiple-cursors.el
|
||||
|
||||
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 though, I've been using it since 2011 with
|
||||
great success and much merriment.
|
||||
|
||||
## Maintenance warning
|
||||
|
||||
I use this package every day, and have been doing so for years. It just works.
|
||||
At least, it works for all my use cases. And if it breaks somehow, I fix it.
|
||||
|
||||
However, it has become painfully clear to me that I don't have time to fix
|
||||
problems I don't have. It's been years since I could keep pace with the issues
|
||||
and pull requests. Whenever I try, I keep getting feedback that my fix isn't
|
||||
good enough by some standard I don't particularly care about.
|
||||
|
||||
So, I have closed the issue tracker and the pull requests. I hope you can
|
||||
happily use this package, just like I do. If it doesn't work for you, then I'm
|
||||
sorry. Thankfully Emacs is infinitely malleable, you can probably fix it
|
||||
yourself.
|
||||
|
||||
TLDR: *I am still maintaining this package*, but I am no longer crowdsourcing a list of issues.
|
||||
|
||||
## Installation
|
||||
|
||||
I highly recommend installing multiple-cursors through `package.el`.
|
||||
|
||||
It's available on [MELPA](http://melpa.org/), [MELPA Stable](http://stable.melpa.org) and
|
||||
[NonGNU ELPA](https://elpa.nongnu.org/nongnu/multiple-cursors.html) (enabled by default
|
||||
from Emacs 28 onwards):
|
||||
|
||||
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
|
||||
|
||||
Start out with:
|
||||
@ -35,42 +71,119 @@ insert a newline in multiple-cursors-mode, use `C-j`.
|
||||
|
||||
You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.com/e13.html).
|
||||
|
||||
## More commands to play around with
|
||||
## Command overview
|
||||
|
||||
I've set up my key-bindings like so:
|
||||
### Mark one more occurrence
|
||||
|
||||
;; From active region to multiple cursors:
|
||||
(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
|
||||
(global-set-key (kbd "C-S-c C-e") 'mc/edit-ends-of-lines)
|
||||
(global-set-key (kbd "C-S-c C-a") 'mc/edit-beginnings-of-lines)
|
||||
| Command | Description |
|
||||
|-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `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-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-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-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 occurrences. |
|
||||
| `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. |
|
||||
|
||||
When you have an active region that spans multiple lines, the preceeding three
|
||||
commands will add one cursor to each line.
|
||||
### Juggle around with the current cursors
|
||||
|
||||
;; Rectangular region mode
|
||||
(global-set-key (kbd "H-SPC") 'set-rectangular-region-anchor)
|
||||
| Command | Description |
|
||||
|---------------------------------|--------------------------------------------------------------------|
|
||||
| `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 occurrence down. |
|
||||
| `mc/skip-to-previous-like-this` | Remove the cursor furthest up, marking the next occurrence up. |
|
||||
|
||||
Think of this one as `set-mark` except you're marking a rectangular region. It is
|
||||
an exceedingly quick way of adding multiple cursors to multiple lines.
|
||||
### Mark many occurrences
|
||||
|
||||
;; Mark more like this
|
||||
(global-set-key (kbd "M-æ") 'mc/mark-all-like-this)
|
||||
(global-set-key (kbd "C-å") 'mc/mark-previous-like-this)
|
||||
(global-set-key (kbd "C-æ") 'mc/mark-next-like-this)
|
||||
(global-set-key (kbd "C-Æ") 'mc/mark-more-like-this-extended)
|
||||
(global-set-key (kbd "M-å") 'mc/mark-all-in-region)
|
||||
| Command | Description |
|
||||
|------------------------------------------|-------------------------------------------------------------------------------------|
|
||||
| `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-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-in-region` | Prompts for a string to match in the region, adding cursors to all of them. |
|
||||
| `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-symbols-like-this-in-defun` | Like `mc/mark-all-like-this-in-defun` but only for whole symbols. |
|
||||
| `mc/mark-all-dwim` | Tries to be smart about marking everything you want. Can be pressed multiple times. |
|
||||
|
||||
Okay, yes, I have a crazy norwegian keyboard. Regardless, these will look at
|
||||
whatever you've got selected at the moment, and mark more places like that in
|
||||
the buffer.
|
||||
### Special
|
||||
|
||||
| Command | Description |
|
||||
|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `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/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. |
|
||||
| `mc/vertical-align` | Aligns all cursors vertically with a given CHARACTER to the one with the highest column number (the rightest). (Might not behave as intended if more than one cursors are on the same line.) |
|
||||
| `mc/vertical-align-with-space` | Aligns all cursors with whitespace like `mc/vertical-align` does. |
|
||||
|
||||
## Tips and tricks
|
||||
|
||||
- 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
|
||||
insert a newline in multiple-cursors-mode, use `C-j`.
|
||||
|
||||
- `(define-key mc/keymap (kbd "<return>") nil)` will make `<return>` insert a
|
||||
newline; multiple-cursors-mode can still be disabled with `C-g`.
|
||||
|
||||
- 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` 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 occurrence
|
||||
|
||||
- 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.
|
||||
|
||||
- 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
|
||||
when the region is active, you can try [region-bindings-mode](https://github.com/fgallina/region-bindings-mode).
|
||||
|
||||
- There is a special hook that is run when the mode is diabled
|
||||
(which is equivalent to the number of cursors going back to 1):
|
||||
`multiple-cursors-mode-disabled-hook`
|
||||
|
||||
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`.
|
||||
|
||||
## Scrolling
|
||||
### Binding mouse events
|
||||
|
||||
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`.
|
||||
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
|
||||
|
||||
@ -84,12 +197,17 @@ the location with:
|
||||
|
||||
(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
|
||||
|
||||
* 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.
|
||||
* Commands run with `M-x` won't be repeated for all cursors.
|
||||
If you want this functionality, you can use [phi-search](https://github.com/zk-phi/phi-search).
|
||||
* 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.
|
||||
* Redo might screw with your cursors. Undo works very well.
|
||||
@ -104,19 +222,35 @@ You'll find the repo at:
|
||||
|
||||
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
|
||||
$ git submodule update --init
|
||||
$ cask
|
||||
|
||||
Run the tests with:
|
||||
|
||||
$ ./util/ecukes/ecukes --graphical
|
||||
$ ./run-tests.sh
|
||||
|
||||
## Contributors
|
||||
|
||||
* [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.
|
||||
* [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`
|
||||
* [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!
|
||||
|
||||
## License
|
||||
|
||||
Copyright (C) 2012 Magnar Sveen
|
||||
Copyright (C) 2012-2016 Magnar Sveen
|
||||
|
||||
Author: Magnar Sveen <magnars@gmail.com>
|
||||
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 press "C-S-c C-S-c"
|
||||
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
|
||||
"""
|
||||
|
73
features/hide-unmatched-lines.feature
Normal file
73
features/hide-unmatched-lines.feature
Normal file
@ -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
|
||||
|
||||
"""
|
25
features/insert-letters.feature
Normal file
25
features/insert-letters.feature
Normal file
@ -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)"
|
40
features/insert-numbers.feature
Normal file
40
features/insert-numbers.feature
Normal file
@ -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)"
|
94
features/mark-all-dwim-html.feature
Normal file
94
features/mark-all-dwim-html.feature
Normal file
@ -0,0 +1,94 @@
|
||||
Feature: Mark all do-what-I-mean (html)
|
||||
|
||||
Background:
|
||||
Given I turn on html-mode
|
||||
And I turn on delete-selection-mode
|
||||
And I insert:
|
||||
"""
|
||||
<body>
|
||||
<div class="abc"> def </div>
|
||||
<div class="ghi"> jkl </div>
|
||||
</body>
|
||||
"""
|
||||
|
||||
Scenario: Marks tags in html-mode, from front
|
||||
When I go to the front of the word "abc"
|
||||
And I press "M-b"
|
||||
And I press "M-b"
|
||||
And I press "M-$"
|
||||
And I type "h1"
|
||||
Then I should see:
|
||||
"""
|
||||
<body>
|
||||
<h1 class="abc"> def </h1>
|
||||
<div class="ghi"> jkl </div>
|
||||
</body>
|
||||
"""
|
||||
|
||||
Scenario: Marks tags in html-mode, from back
|
||||
When I go to the end of the word "jkl"
|
||||
And I press "M-f"
|
||||
And I press "M-$"
|
||||
And I type "h1"
|
||||
Then I should see:
|
||||
"""
|
||||
<body>
|
||||
<div class="abc"> def </div>
|
||||
<h1 class="ghi"> jkl </h1>
|
||||
</body>
|
||||
"""
|
||||
|
||||
Scenario: Marks tags in html-mode, from outside front
|
||||
When I go to the front of the word "abc"
|
||||
And I press "M-b"
|
||||
And I press "M-b"
|
||||
And I press "C-b"
|
||||
And I press "M-$"
|
||||
And I type "h1"
|
||||
Then I should see:
|
||||
"""
|
||||
<body>
|
||||
<h1 class="abc"> def </h1>
|
||||
<div class="ghi"> jkl </div>
|
||||
</body>
|
||||
"""
|
||||
|
||||
Scenario: Marks tags in html-mode, from outside back
|
||||
When I go to the end of the word "jkl"
|
||||
And I press "M-f"
|
||||
And I press "C-f"
|
||||
And I press "M-$"
|
||||
And I type "h1"
|
||||
Then I should see:
|
||||
"""
|
||||
<body>
|
||||
<div class="abc"> def </div>
|
||||
<h1 class="ghi"> jkl </h1>
|
||||
</body>
|
||||
"""
|
||||
|
||||
Scenario: Marks words in html-mode
|
||||
When I go to the front of the word "abc"
|
||||
And I press "M-$"
|
||||
And I type "def"
|
||||
Then I should see:
|
||||
"""
|
||||
<body>
|
||||
<div class="def"> def </div>
|
||||
<div class="ghi"> jkl </div>
|
||||
</body>
|
||||
"""
|
||||
|
||||
Scenario: Marks words in html-mode
|
||||
When I go to the front of the word "abc"
|
||||
And I press "M-$"
|
||||
And I type "def"
|
||||
And I press "M-$"
|
||||
And I type "hah"
|
||||
Then I should see:
|
||||
"""
|
||||
<body>
|
||||
<div class="hah"> hah </div>
|
||||
<div class="ghi"> jkl </div>
|
||||
</body>
|
||||
"""
|
90
features/mark-all-dwim.feature
Normal file
90
features/mark-all-dwim.feature
Normal file
@ -0,0 +1,90 @@
|
||||
Feature: Mark all do-what-I-mean
|
||||
|
||||
Background:
|
||||
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))
|
||||
|
||||
"""
|
||||
|
||||
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
|
||||
When I go to the end of the word "abc"
|
||||
And I press "M-f"
|
||||
And I press "M-$"
|
||||
And I press "M-$"
|
||||
And I type "hmm"
|
||||
Then I should see:
|
||||
"""
|
||||
(defun abc (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"
|
||||
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
|
||||
Given I turn on delete-selection-mode
|
||||
When I insert "Here's text, text and text"
|
||||
@ -54,6 +62,14 @@ Feature: Marking multiple parts of the buffer
|
||||
And I type "sentence"
|
||||
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
|
||||
Given I turn on delete-selection-mode
|
||||
When I insert "Here's text, text and text"
|
||||
@ -94,3 +110,51 @@ Feature: Marking multiple parts of the buffer
|
||||
And I type "more"
|
||||
Then I should have 2 cursors
|
||||
And I should see "Here's more, more and text"
|
||||
|
||||
Scenario: Marking without an active region
|
||||
When I insert:
|
||||
"""
|
||||
aaa
|
||||
bbb
|
||||
ccc
|
||||
"""
|
||||
And I go to the front of the word "bbb"
|
||||
And I press "C->"
|
||||
And I type "_"
|
||||
Then I should have 2 cursors
|
||||
And I should see:
|
||||
"""
|
||||
aaa
|
||||
_bbb
|
||||
_ccc
|
||||
"""
|
||||
|
||||
Scenario: Increasing number of cursors without an active region
|
||||
When I insert:
|
||||
"""
|
||||
aaa
|
||||
bbb
|
||||
ccc
|
||||
"""
|
||||
And I go to the front of the word "bbb"
|
||||
And I press "C->"
|
||||
And I press "C-<"
|
||||
And i press "C-f"
|
||||
And I type "_"
|
||||
Then I should have 3 cursors
|
||||
And I should see:
|
||||
"""
|
||||
a_aa
|
||||
b_bb
|
||||
c_cc
|
||||
"""
|
||||
|
||||
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"
|
||||
|
||||
|
88
features/mark-pop.feature
Normal file
88
features/mark-pop.feature
Normal file
@ -0,0 +1,88 @@
|
||||
Feature: Popping cursors off of the mark stack
|
||||
|
||||
Scenario: Single pop
|
||||
Given I turn off transient-mark-mode
|
||||
And I insert:
|
||||
"""
|
||||
hello
|
||||
there
|
||||
"""
|
||||
And I go to the front of the word "hello"
|
||||
And I set the mark
|
||||
And I go to the front of the word "there"
|
||||
And I press "M-x mc/mark-pop"
|
||||
Then I should have 2 cursors
|
||||
|
||||
Scenario: Multiple pops
|
||||
Given I turn off transient-mark-mode
|
||||
And I insert:
|
||||
"""
|
||||
hello
|
||||
there, my friend
|
||||
"""
|
||||
And I go to the front of the word "hello"
|
||||
And I set the mark
|
||||
And I go to the front of the word "my"
|
||||
And I set the mark
|
||||
And I go to the front of the word "friend"
|
||||
And I press "M-x mc/mark-pop"
|
||||
And I press "M-x mc/mark-pop"
|
||||
Then I should have 3 cursors
|
||||
|
||||
Scenario: Discard identical mark and point
|
||||
Given I turn off transient-mark-mode
|
||||
And I insert:
|
||||
"""
|
||||
hello
|
||||
there, my friend
|
||||
"""
|
||||
And I go to the front of the word "hello"
|
||||
And I set the mark
|
||||
And I go to the front of the word "my"
|
||||
And I set the mark
|
||||
And I go to the front of the word "friend"
|
||||
And I set the mark
|
||||
And I press "M-x mc/mark-pop"
|
||||
And I press "M-x mc/mark-pop"
|
||||
Then I should have 3 cursors
|
||||
|
||||
Scenario: Changing the text
|
||||
Given I turn off transient-mark-mode
|
||||
And I insert:
|
||||
"""
|
||||
hello
|
||||
there, my friend
|
||||
"""
|
||||
And I go to the front of the word "hello"
|
||||
And I set the mark
|
||||
And I go to the front of the word "my"
|
||||
And I set the mark
|
||||
And I go to the front of the word "friend"
|
||||
And I press "M-x mc/mark-pop"
|
||||
And I press "M-x mc/mark-pop"
|
||||
And I type "!"
|
||||
Then I should see:
|
||||
"""
|
||||
!hello
|
||||
there, !my !friend
|
||||
"""
|
||||
|
||||
Scenario: With transient-mark-mode
|
||||
And I insert:
|
||||
"""
|
||||
hello
|
||||
there, my friend
|
||||
"""
|
||||
And I go to the front of the word "hello"
|
||||
And I press "C-@ C-@"
|
||||
And I go to the front of the word "my"
|
||||
And I press "C-@ C-@"
|
||||
And I go to the front of the word "friend"
|
||||
And I press "M-x mc/mark-pop"
|
||||
And I press "M-x mc/mark-pop"
|
||||
And I type "!"
|
||||
Then I should see:
|
||||
"""
|
||||
!hello
|
||||
there, !my !friend
|
||||
"""
|
137
features/mark-things.feature
Normal file
137
features/mark-things.feature
Normal file
@ -0,0 +1,137 @@
|
||||
Feature: Mark things
|
||||
|
||||
Scenario: Mark all symbols like this with select
|
||||
Given I turn on emacs-lisp-mode
|
||||
And I turn on delete-selection-mode
|
||||
And I insert:
|
||||
"""
|
||||
(defun abc (ghi) (message ghi))
|
||||
(defun def (ghi) (message some-other-ghi))
|
||||
"""
|
||||
When I select "ghi"
|
||||
And I mark all symbols like this
|
||||
And I type "hmm"
|
||||
Then I should see:
|
||||
"""
|
||||
(defun abc (hmm) (message hmm))
|
||||
(defun def (hmm) (message some-other-ghi))
|
||||
"""
|
||||
|
||||
Scenario: Mark all words like this with select
|
||||
Given I turn on emacs-lisp-mode
|
||||
And I turn on delete-selection-mode
|
||||
And I insert:
|
||||
"""
|
||||
(defun abc (ghi) (message ghi))
|
||||
(defun def (ghi) (message some-other-ghi))
|
||||
"""
|
||||
When I select "ghi"
|
||||
And I mark all words like this
|
||||
And I type "hmm"
|
||||
Then I should see:
|
||||
"""
|
||||
(defun abc (hmm) (message hmm))
|
||||
(defun def (hmm) (message some-other-hmm))
|
||||
"""
|
||||
|
||||
Scenario: Mark all symbols like this in defun with select
|
||||
Given I turn on emacs-lisp-mode
|
||||
And I turn on delete-selection-mode
|
||||
And I insert:
|
||||
"""
|
||||
(defun abc (ghi) (message ghi))
|
||||
(defun def (ghi) (message some-other-ghi))
|
||||
"""
|
||||
When I select "ghi"
|
||||
And I mark all symbols like this in defun
|
||||
And I type "hmm"
|
||||
Then I should see:
|
||||
"""
|
||||
(defun abc (hmm) (message hmm))
|
||||
(defun def (ghi) (message some-other-ghi))
|
||||
"""
|
||||
|
||||
Scenario: Mark all words like this in defun with select
|
||||
Given I turn on emacs-lisp-mode
|
||||
And I turn on delete-selection-mode
|
||||
And I insert:
|
||||
"""
|
||||
(defun abc (ghi) (message ghi))
|
||||
(defun def (ghi) (message some-other-ghi))
|
||||
"""
|
||||
When I select "ghi"
|
||||
And I mark all words like this in defun
|
||||
And I type "hmm"
|
||||
Then I should see:
|
||||
"""
|
||||
(defun abc (hmm) (message hmm))
|
||||
(defun def (ghi) (message some-other-ghi))
|
||||
"""
|
||||
|
||||
Scenario: Mark all symbols like this with no select
|
||||
Given I turn on emacs-lisp-mode
|
||||
And I turn on delete-selection-mode
|
||||
And I insert:
|
||||
"""
|
||||
(defun abc (ghi) (message ghi))
|
||||
(defun def (ghi) (message some-other-ghi))
|
||||
"""
|
||||
When I go to word "ghi"
|
||||
And I mark all symbols like this
|
||||
And I type "hmm"
|
||||
Then I should see:
|
||||
"""
|
||||
(defun abc (hmm) (message hmm))
|
||||
(defun def (hmm) (message some-other-ghi))
|
||||
"""
|
||||
|
||||
Scenario: Mark all words like this with no select
|
||||
Given I turn on emacs-lisp-mode
|
||||
And I turn on delete-selection-mode
|
||||
And I insert:
|
||||
"""
|
||||
(defun abc (ghi) (message ghi))
|
||||
(defun def (ghi) (message some-other-ghi))
|
||||
"""
|
||||
When I go to word "ghi"
|
||||
And I mark all words like this
|
||||
And I type "hmm"
|
||||
Then I should see:
|
||||
"""
|
||||
(defun abc (hmm) (message hmm))
|
||||
(defun def (hmm) (message some-other-hmm))
|
||||
"""
|
||||
|
||||
Scenario: Mark all symbols like this in defun with no select
|
||||
Given I turn on emacs-lisp-mode
|
||||
And I turn on delete-selection-mode
|
||||
And I insert:
|
||||
"""
|
||||
(defun abc (ghi) (message ghi))
|
||||
(defun def (ghi) (message some-other-ghi))
|
||||
"""
|
||||
When I go to word "ghi"
|
||||
And I mark all symbols like this in defun
|
||||
And I type "hmm"
|
||||
Then I should see:
|
||||
"""
|
||||
(defun abc (hmm) (message hmm))
|
||||
(defun def (ghi) (message some-other-ghi))
|
||||
"""
|
||||
|
||||
Scenario: Mark all words like this in defun with no select
|
||||
Given I turn on emacs-lisp-mode
|
||||
And I turn on delete-selection-mode
|
||||
And I insert:
|
||||
"""
|
||||
(defun abc (ghi) (message ghi))
|
||||
(defun def (ghi) (message some-other-ghi))
|
||||
"""
|
||||
When I go to word "ghi"
|
||||
And I mark all words like this in defun
|
||||
And I type "hmm"
|
||||
Then I should see:
|
||||
"""
|
||||
(defun abc (hmm) (message hmm))
|
||||
(defun def (ghi) (message some-other-ghi))
|
||||
"""
|
@ -50,6 +50,13 @@ Feature: Multiple cursors core
|
||||
And I press "C-!"
|
||||
Then I should see "This aatext contains the word aatext twice"
|
||||
|
||||
Scenario: Unknown command with multiple read: yes, do for all
|
||||
Given I have bound C-! to a new command that inserts two read-chars
|
||||
And I have cursors at "text" in "This text contains the word text twice"
|
||||
When I press "C-! b c y"
|
||||
And I press "C-! d e"
|
||||
Then I should see "This bcdetext contains the word bcdetext twice"
|
||||
|
||||
Scenario: Unknown command: no, don't do for all
|
||||
Given I have bound C-! to another new command that inserts "a"
|
||||
And I have cursors at "text" in "This text contains the word text twice"
|
||||
@ -57,6 +64,28 @@ Feature: Multiple cursors core
|
||||
And I press "C-!"
|
||||
Then I should see "This aatext contains the word text twice"
|
||||
|
||||
Scenario: Multiple supported M-x command (forward-word in this case)
|
||||
Given I have cursors at "text" in "This text contains the word text twice"
|
||||
And I type "("
|
||||
And I press "M-x forward-word"
|
||||
And I press "M-x forward-word"
|
||||
And I type ")"
|
||||
Then I should see "This (text contains) the word (text twice)"
|
||||
|
||||
Scenario: Unknown M-x command: yes, do for all
|
||||
Given I have cursors at "text" in "This text contains the word text twice"
|
||||
And I press "C-SPC"
|
||||
And I press "M-f"
|
||||
And I press "M-x upcase-dwim RET y"
|
||||
Then I should see "This TEXT contains the word TEXT twice"
|
||||
|
||||
Scenario: Unknown M-x command: no, don't do for all
|
||||
Given I have cursors at "text" in "This text contains the word text twice"
|
||||
And I press "C-SPC"
|
||||
And I press "M-f"
|
||||
And I press "M-x upcase-dwim RET n"
|
||||
Then I should see "This TEXT contains the word text twice"
|
||||
|
||||
Scenario: Undo
|
||||
Given I have cursors at "text" in "This text contains the word text twice"
|
||||
When I press "M-f"
|
||||
@ -115,10 +144,27 @@ Feature: Multiple cursors core
|
||||
And I go to the front of the word "text"
|
||||
And I press "C-SPC"
|
||||
And I press "M-f"
|
||||
And I press "C->"
|
||||
And I mark next like this
|
||||
And I type "!"
|
||||
Then I should see "This ! contains the word ! twice"
|
||||
|
||||
Scenario: wrap-region (function turns to keyboard macros)
|
||||
Given I turn on wrap-region-mode
|
||||
And I insert "This text contains the word text twice"
|
||||
And I go to the front of the word "text"
|
||||
And I press "C-M-SPC"
|
||||
And I mark next like this
|
||||
And I press "C-g"
|
||||
And I type "("
|
||||
Then I should see "This (text contains the word (text twice"
|
||||
|
||||
Scenario: Bound keyboard macros
|
||||
Given I have bound C-! to a keyboard macro that insert "_"
|
||||
And I have cursors at "text" in "This text contains the word text twice"
|
||||
When I press "C-!"
|
||||
When I press "C-!"
|
||||
Then I should see "This __text contains the word __text twice"
|
||||
|
||||
Scenario: Interprogram paste
|
||||
Given I have cursors at "text" in "This text contains the word text twice"
|
||||
When I copy "external" in another program
|
||||
@ -141,3 +187,31 @@ Feature: Multiple cursors core
|
||||
contains
|
||||
twice
|
||||
"""
|
||||
|
||||
Scenario: Looping forwards around cursors
|
||||
Given I have cursors at "_" in "1_34567_9"
|
||||
And I press "C-v"
|
||||
And I press "C-v"
|
||||
And I press "C-v"
|
||||
Then the cursor should be at point "8"
|
||||
|
||||
Scenario: Looping 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
|
||||
Given I have cursors at "_" in "1_34567_9"
|
||||
And I press "M-v"
|
||||
And I press "M-v"
|
||||
Then the cursor should be at point "2"
|
||||
|
||||
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"
|
||||
|
39
features/repeat-command.feature
Normal file
39
features/repeat-command.feature
Normal file
@ -0,0 +1,39 @@
|
||||
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 type "n"
|
||||
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 set mc/always-run-for-all 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)"
|
19
features/sort-and-reverse.feature
Normal file
19
features/sort-and-reverse.feature
Normal file
@ -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$"
|
||||
(lambda ()
|
||||
(delete-selection-mode 1)))
|
||||
|
||||
(Given "^I turn off transient-mark-mode$"
|
||||
(lambda ()
|
||||
(transient-mark-mode -1)))
|
||||
|
||||
(Then "^I should have \\([0-9]+\\) cursors$"
|
||||
(lambda (num)
|
||||
(let ((actual (mc/num-cursors)))
|
||||
(assert (eq (string-to-number num) actual) nil
|
||||
"Expected to have %s cursors, but was %d." num actual))))
|
||||
(cl-assert (eq (string-to-number num) actual) nil
|
||||
"Expected to have %s cursors, but was %d." num actual))))
|
||||
|
||||
(Then "^I should have one cursor$"
|
||||
(lambda ()
|
||||
(assert (not multiple-cursors-mode) nil
|
||||
"Expected to have one cursor, but multiple-cursors-mode is still active.")
|
||||
(assert (eq 1 (mc/num-cursors)) nil
|
||||
"Expected to have one cursor, but there are still fake cursor overlays.")))
|
||||
(cl-assert (not multiple-cursors-mode) nil
|
||||
"Expected to have one cursor, but multiple-cursors-mode is still active.")
|
||||
(cl-assert (eq 1 (mc/num-cursors)) nil
|
||||
"Expected to have one cursor, but there are still fake cursor overlays.")))
|
||||
|
||||
(Then "^rectangular-region-mode should be off$"
|
||||
(lambda ()
|
||||
(assert (not rectangular-region-mode) nil
|
||||
"Expected rectangular-region-mode mode to be off, but wasn't.")))
|
||||
(lambda ()
|
||||
(cl-assert (not rectangular-region-mode) nil
|
||||
"Expected rectangular-region-mode mode to be off, but wasn't.")))
|
||||
|
||||
(Then "^rectangular-region-mode should be on$"
|
||||
(lambda ()
|
||||
(assert rectangular-region-mode nil
|
||||
"Expected rectangular-region-mode mode to be on, but wasn't.")))
|
||||
(lambda ()
|
||||
(cl-assert rectangular-region-mode nil
|
||||
"Expected rectangular-region-mode mode to be on, but wasn't.")))
|
||||
|
||||
(When "^I press \"\\(.+\\)\"$"
|
||||
(lambda (keybinding)
|
||||
@ -45,6 +96,17 @@
|
||||
(mc/mark-all-like-this)
|
||||
(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$"
|
||||
(lambda (text)
|
||||
(lexical-let ((text text))
|
||||
@ -68,25 +130,70 @@
|
||||
(defun mc-test-temp-command-2 () (interactive) (insert ins))
|
||||
(global-set-key (kbd "C-!") 'mc-test-temp-command-2))))
|
||||
|
||||
(Given "^I have bound C-! to a new command that inserts two read-chars$"
|
||||
(lambda ()
|
||||
(defun mc-test-temp-command-3 () (interactive) (insert (read-char "first: ")) (insert (read-char "second: ")))
|
||||
(global-set-key (kbd "C-!") 'mc-test-temp-command-3)))
|
||||
|
||||
(Given "^I have bound C-! to a keyboard macro that insert \"_\"$"
|
||||
(lambda ()
|
||||
(fset 'mc-test-temp-kmacro "\C-q_")
|
||||
(global-set-key (kbd "C-!") 'mc-test-temp-kmacro)))
|
||||
|
||||
(When "^I go to character \"\\(.+\\)\"$"
|
||||
(lambda (char)
|
||||
(goto-char (point-min))
|
||||
(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"))
|
||||
(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 \"\\(.+\\)\"$"
|
||||
(lambda (pos word)
|
||||
(goto-char (point-min))
|
||||
(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"))
|
||||
(assert search nil message word (espuds-buffer-contents))
|
||||
(cl-assert search nil message word (espuds-buffer-contents))
|
||||
(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 \"\\(.+\\)\"$"
|
||||
(lambda (text)
|
||||
(goto-char (point-max))
|
||||
(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))
|
||||
(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:
|
||||
|
@ -7,10 +7,12 @@
|
||||
(add-to-list 'load-path multiple-cursors-root-path)
|
||||
(add-to-list 'load-path multiple-cursors-util-path)
|
||||
(add-to-list 'load-path (expand-file-name "espuds" multiple-cursors-util-path))
|
||||
(add-to-list 'load-path (expand-file-name "vendor" multiple-cursors-util-path))
|
||||
|
||||
(require 'multiple-cursors)
|
||||
(require 'espuds)
|
||||
(require 'ert)
|
||||
(require 'wrap-region)
|
||||
|
||||
(defun mc/save-lists ()) ;; redefine to do nothing when running tests
|
||||
|
||||
@ -19,9 +21,19 @@
|
||||
(multiple-cursors-mode 0)
|
||||
(rectangular-region-mode 0)
|
||||
(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-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-dwim)
|
||||
(global-set-key (kbd "C-$") 'mc/mark-all-dwim)
|
||||
(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 "H-SPC") 'set-rectangular-region-anchor)
|
||||
(switch-to-buffer
|
||||
@ -31,7 +43,10 @@
|
||||
(cua-mode 0)
|
||||
(delete-selection-mode 0)
|
||||
(subword-mode 0)
|
||||
(wrap-region-mode 0)
|
||||
(setq set-mark-default-inactive nil)
|
||||
(deactivate-mark))
|
||||
(deactivate-mark)
|
||||
(setq mc/cmds-to-run-for-all nil)
|
||||
(setq mc/cmds-to-run-once nil))
|
||||
|
||||
(After)
|
||||
|
27
features/vertical-align.feature
Normal file
27
features/vertical-align.feature
Normal file
@ -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
|
||||
"""
|
@ -1,6 +1,6 @@
|
||||
;;; mc-cycle-cursors.el
|
||||
;;; mc-cycle-cursors.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2012 Magnar Sveen
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||
;; Keywords: editing cursors
|
||||
@ -28,11 +28,9 @@
|
||||
|
||||
(require 'multiple-cursors-core)
|
||||
|
||||
(eval-when-compile (require 'cl))
|
||||
|
||||
(defun mc/next-cursor-after-point ()
|
||||
(defun mc/next-fake-cursor-after-point ()
|
||||
(let ((pos (point))
|
||||
(next-pos (point-max))
|
||||
(next-pos (1+ (point-max)))
|
||||
next)
|
||||
(mc/for-each-fake-cursor
|
||||
(let ((cursor-pos (overlay-get cursor 'point)))
|
||||
@ -42,9 +40,9 @@
|
||||
(setq next cursor))))
|
||||
next))
|
||||
|
||||
(defun mc/prev-cursor-before-point ()
|
||||
(defun mc/prev-fake-cursor-before-point ()
|
||||
(let ((pos (point))
|
||||
(prev-pos (point-min))
|
||||
(prev-pos (1- (point-min)))
|
||||
prev)
|
||||
(mc/for-each-fake-cursor
|
||||
(let ((cursor-pos (overlay-get cursor 'point)))
|
||||
@ -54,27 +52,72 @@
|
||||
(setq prev cursor))))
|
||||
prev))
|
||||
|
||||
(defcustom mc/cycle-looping-behaviour 'continue
|
||||
"What to do if asked to cycle beyond the last cursor or before the first cursor."
|
||||
:type '(radio (const :tag "Loop around to beginning/end of document." continue)
|
||||
(const :tag "Warn and then loop around." warn)
|
||||
(const :tag "Signal an error." error)
|
||||
(const :tag "Don't loop." stop))
|
||||
:group 'multiple-cursors)
|
||||
|
||||
(defun mc/handle-loop-condition (error-message)
|
||||
(cl-ecase mc/cycle-looping-behaviour
|
||||
(error (error error-message))
|
||||
(warn (message error-message))
|
||||
(continue 'continue)
|
||||
(stop 'stop)))
|
||||
|
||||
(defun mc/first-fake-cursor-after (point)
|
||||
"Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)."
|
||||
(let* ((cursors (mc/all-fake-cursors))
|
||||
(cursors-after-point (cl-remove-if (lambda (cursor)
|
||||
(< (mc/cursor-beg cursor) point))
|
||||
cursors))
|
||||
(cursors-in-order (cl-sort cursors-after-point '< :key 'mc/cursor-beg)))
|
||||
(car cursors-in-order)))
|
||||
|
||||
(defun mc/last-fake-cursor-before (point)
|
||||
"Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)."
|
||||
(let* ((cursors (mc/all-fake-cursors))
|
||||
(cursors-before-point (cl-remove-if (lambda (cursor)
|
||||
(> (mc/cursor-end cursor) point))
|
||||
cursors))
|
||||
(cursors-in-order (cl-sort cursors-before-point '> :key 'mc/cursor-end)))
|
||||
(car cursors-in-order)))
|
||||
|
||||
(cl-defun mc/cycle (next-cursor fallback-cursor loop-message)
|
||||
(when (null next-cursor)
|
||||
(when (eql 'stop (mc/handle-loop-condition loop-message))
|
||||
(cond
|
||||
((fboundp 'cl-return-from)
|
||||
(cl-return-from mc/cycle nil))
|
||||
((fboundp 'return-from)
|
||||
(cl-return-from mc/cycle nil))))
|
||||
(setf next-cursor fallback-cursor))
|
||||
(mc/create-fake-cursor-at-point)
|
||||
(mc/pop-state-from-overlay next-cursor)
|
||||
(recenter))
|
||||
|
||||
(defun mc/cycle-forward ()
|
||||
(interactive)
|
||||
(let ((next-cursor (mc/next-cursor-after-point)))
|
||||
(unless next-cursor
|
||||
(error "We're already at the last cursor"))
|
||||
(mc/create-fake-cursor-at-point)
|
||||
(mc/pop-state-from-overlay next-cursor)
|
||||
(recenter)))
|
||||
(mc/cycle (mc/next-fake-cursor-after-point)
|
||||
(mc/first-fake-cursor-after (point-min))
|
||||
"We're already at the last cursor."))
|
||||
|
||||
(defun mc/cycle-backward ()
|
||||
(interactive)
|
||||
(let ((prev-cursor (mc/prev-cursor-before-point)))
|
||||
(unless prev-cursor
|
||||
(error "We're already at the first cursor"))
|
||||
(mc/create-fake-cursor-at-point)
|
||||
(mc/pop-state-from-overlay prev-cursor)
|
||||
(recenter)))
|
||||
(mc/cycle (mc/prev-fake-cursor-before-point)
|
||||
(mc/last-fake-cursor-before (point-max))
|
||||
"We're already at the last cursor"))
|
||||
|
||||
(define-key mc/keymap (kbd "C-v") 'mc/cycle-forward)
|
||||
(define-key mc/keymap (kbd "M-v") 'mc/cycle-backward)
|
||||
|
||||
(provide 'mc-cycle-cursors)
|
||||
|
||||
|
||||
;; Local Variables:
|
||||
;; coding: utf-8
|
||||
;; End:
|
||||
|
||||
;;; mc-cycle-cursors.el ends here
|
||||
|
@ -1,6 +1,6 @@
|
||||
;;; mc-edit-lines.el
|
||||
;;; mc-edit-lines.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2012 Magnar Sveen
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||
;; Keywords: editing cursors
|
||||
@ -29,26 +29,65 @@
|
||||
|
||||
(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
|
||||
(defun mc/edit-lines ()
|
||||
(defun mc/edit-lines (&optional arg)
|
||||
"Add one cursor to each line of the active region.
|
||||
Starts from mark and moves in straight down or up towards the
|
||||
line point is on."
|
||||
(interactive)
|
||||
(when (not (use-region-p))
|
||||
(error "Mark a set of lines first."))
|
||||
line point is on.
|
||||
|
||||
What is done with lines which are not long enough is governed by
|
||||
`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")
|
||||
(unless mark-active
|
||||
(error "Mark a set of lines first"))
|
||||
(mc/remove-fake-cursors)
|
||||
(let* ((col (current-column))
|
||||
(point-line (line-number-at-pos))
|
||||
(mark-line (progn (exchange-point-and-mark) (line-number-at-pos)))
|
||||
(direction (if (< point-line mark-line) :up :down)))
|
||||
(point-line (mc/line-number-at-pos))
|
||||
(mark-line (progn (exchange-point-and-mark) (mc/line-number-at-pos)))
|
||||
(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)
|
||||
(when (and (eq direction :up) (bolp))
|
||||
(forward-line -1)
|
||||
(previous-logical-line 1 nil)
|
||||
(move-to-column col))
|
||||
(while (not (eq (line-number-at-pos) point-line))
|
||||
(mc/create-fake-cursor-at-point)
|
||||
(if (eq direction :up) (forward-line -1) (forward-line 1))
|
||||
;; Add the cursors
|
||||
(while (not (eq (mc/line-number-at-pos) point-line))
|
||||
;; Pad the line
|
||||
(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))
|
||||
(multiple-cursors-mode)))
|
||||
|
||||
@ -57,16 +96,14 @@ line point is on."
|
||||
"Add one cursor to the end of each line in the active region."
|
||||
(interactive)
|
||||
(mc/edit-lines)
|
||||
(mc/execute-command-for-all-fake-cursors 'end-of-line)
|
||||
(end-of-line))
|
||||
(mc/execute-command-for-all-cursors 'end-of-line))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/edit-beginnings-of-lines ()
|
||||
"Add one cursor to the beginning of each line in the active region."
|
||||
(interactive)
|
||||
(mc/edit-lines)
|
||||
(mc/execute-command-for-all-fake-cursors 'beginning-of-line)
|
||||
(beginning-of-line))
|
||||
(mc/execute-command-for-all-cursors 'beginning-of-line))
|
||||
|
||||
(provide 'mc-edit-lines)
|
||||
|
||||
|
109
mc-hide-unmatched-lines-mode.el
Normal file
109
mc-hide-unmatched-lines-mode.el
Normal file
@ -0,0 +1,109 @@
|
||||
;;; mc-hide-unmatched-lines-mode.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; 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\""
|
||||
:init-value nil
|
||||
:lighter " hu"
|
||||
:keymap 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 instead of hidden 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))
|
||||
|
||||
(define-key mc/keymap (kbd "C-'") 'mc-hide-unmatched-lines-mode)
|
||||
|
||||
(provide 'mc-hide-unmatched-lines-mode)
|
721
mc-mark-more.el
721
mc-mark-more.el
@ -1,6 +1,6 @@
|
||||
;;; mc-mark-more.el
|
||||
;;; mc-mark-more.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2012 Magnar Sveen
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||
;; Keywords: editing cursors
|
||||
@ -28,6 +28,8 @@
|
||||
;;; Code:
|
||||
|
||||
(require 'multiple-cursors-core)
|
||||
(require 'thingatpt)
|
||||
(require 'sgml-mode)
|
||||
|
||||
(defun mc/cursor-end (cursor)
|
||||
(if (overlay-get cursor 'mark-active)
|
||||
@ -54,7 +56,7 @@
|
||||
beg))
|
||||
|
||||
(defun mc/furthest-cursor-before-point ()
|
||||
(let ((beg (min (mark) (point)))
|
||||
(let ((beg (if mark-active (min (mark) (point)) (point)))
|
||||
furthest)
|
||||
(mc/for-each-fake-cursor
|
||||
(when (< (mc/cursor-beg cursor) beg)
|
||||
@ -63,7 +65,7 @@
|
||||
furthest))
|
||||
|
||||
(defun mc/furthest-cursor-after-point ()
|
||||
(let ((end (max (mark) (point)))
|
||||
(let ((end (if mark-active (max (mark) (point)) (point)))
|
||||
furthest)
|
||||
(mc/for-each-fake-cursor
|
||||
(when (> (mc/cursor-end cursor) end)
|
||||
@ -71,6 +73,18 @@
|
||||
(setq furthest cursor)))
|
||||
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 ()
|
||||
(let ((strings (list (buffer-substring-no-properties (point) (mark)))))
|
||||
(mc/for-each-fake-cursor
|
||||
@ -79,63 +93,273 @@
|
||||
(mc/cursor-end cursor))))
|
||||
strings))
|
||||
|
||||
(defvar mc/enclose-search-term nil
|
||||
"How should mc/mark-more-* search for more matches?
|
||||
|
||||
Match everything: nil
|
||||
Match only whole words: \\='words
|
||||
Match only whole symbols: \\='symbols
|
||||
|
||||
Use like case-fold-search, don't recommend setting it globally.")
|
||||
|
||||
(defun mc/mark-more-like-this (skip-last direction)
|
||||
(let ((case-fold-search nil)
|
||||
(re (regexp-opt (mc/region-strings) mc/enclose-search-term))
|
||||
(point-out-of-order (cl-ecase direction
|
||||
(forwards (< (point) (mark)))
|
||||
(backwards (not (< (point) (mark))))))
|
||||
(furthest-cursor (cl-ecase direction
|
||||
(forwards (mc/furthest-cursor-after-point))
|
||||
(backwards (mc/furthest-cursor-before-point))))
|
||||
(start-char (cl-ecase direction
|
||||
(forwards (mc/furthest-region-end))
|
||||
(backwards (mc/first-region-start))))
|
||||
(search-function (cl-ecase direction
|
||||
(forwards 'search-forward-regexp)
|
||||
(backwards 'search-backward-regexp)))
|
||||
(match-point-getter (cl-ecase direction
|
||||
(forwards 'match-beginning)
|
||||
(backwards 'match-end))))
|
||||
(if (and skip-last (not furthest-cursor))
|
||||
(error "No cursors to be skipped")
|
||||
(mc/save-excursion
|
||||
(goto-char start-char)
|
||||
(when skip-last
|
||||
(mc/remove-fake-cursor furthest-cursor))
|
||||
(if (funcall search-function re nil t)
|
||||
(progn
|
||||
(push-mark (funcall match-point-getter 0))
|
||||
(when point-out-of-order
|
||||
(exchange-point-and-mark))
|
||||
(mc/create-fake-cursor-at-point))
|
||||
(user-error "no more matches found."))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-next-like-this (arg)
|
||||
"Find and mark the next part of the buffer matching the currently active region
|
||||
If no region is active add a cursor on the next line
|
||||
With negative ARG, delete the last one instead.
|
||||
With zero ARG, skip the last one and mark next."
|
||||
(interactive "p")
|
||||
(unless (region-active-p)
|
||||
(error "Mark a region to match first."))
|
||||
(when (< arg 0)
|
||||
(mc/remove-fake-cursor (mc/furthest-cursor-after-point)))
|
||||
(when (>= arg 0)
|
||||
(let ((case-fold-search nil)
|
||||
(point-first (< (point) (mark)))
|
||||
(re (regexp-opt (mc/region-strings)))
|
||||
(furthest-cursor (mc/furthest-cursor-after-point)))
|
||||
(mc/save-excursion
|
||||
(goto-char (mc/furthest-region-end))
|
||||
(when (= arg 0)
|
||||
(mc/remove-fake-cursor furthest-cursor))
|
||||
(if (search-forward-regexp re nil t)
|
||||
(progn
|
||||
(push-mark (match-beginning 0))
|
||||
(when point-first (exchange-point-and-mark))
|
||||
(mc/create-fake-cursor-at-point))
|
||||
(error "no more found forward")))))
|
||||
(if (> (mc/num-cursors) 1)
|
||||
(multiple-cursors-mode 1)
|
||||
(multiple-cursors-mode 0)))
|
||||
(if (< 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/mark-lines arg 'forwards)))
|
||||
(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
|
||||
(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 add a cursor on the next line
|
||||
With negative ARG, delete the last one instead.
|
||||
With zero ARG, skip the last one and mark next."
|
||||
(interactive "p")
|
||||
(let ((mc/enclose-search-term 'words))
|
||||
(mc/mark-next-like-this arg)))
|
||||
|
||||
;;;###autoload
|
||||
(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 add a cursor on the next line
|
||||
With negative ARG, delete the last one instead.
|
||||
With zero ARG, skip the last one and mark next."
|
||||
(interactive "p")
|
||||
(let ((mc/enclose-search-term 'symbols))
|
||||
(mc/mark-next-like-this arg)))
|
||||
|
||||
;;;###autoload
|
||||
(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 zero ARG, skip the last one and mark next."
|
||||
(interactive "p")
|
||||
(unless (region-active-p)
|
||||
(error "Mark a region to match first."))
|
||||
(when (< arg 0)
|
||||
(mc/remove-fake-cursor (mc/furthest-cursor-before-point)))
|
||||
(when (>= arg 0)
|
||||
(let ((case-fold-search nil)
|
||||
(point-first (< (point) (mark)))
|
||||
(re (regexp-opt (mc/region-strings)))
|
||||
(furthest-cursor (mc/furthest-cursor-before-point)))
|
||||
(mc/save-excursion
|
||||
(goto-char (mc/first-region-start))
|
||||
(when (= arg 0)
|
||||
(mc/remove-fake-cursor furthest-cursor))
|
||||
(if (search-backward-regexp re nil t)
|
||||
(progn
|
||||
(push-mark (match-end 0))
|
||||
(unless point-first (exchange-point-and-mark))
|
||||
(mc/create-fake-cursor-at-point))
|
||||
(error "no more found backward")))))
|
||||
(if (> (mc/num-cursors) 1)
|
||||
(multiple-cursors-mode 1)
|
||||
(multiple-cursors-mode 0)))
|
||||
(if (< arg 0)
|
||||
(let ((cursor (mc/furthest-cursor-before-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/mark-lines arg 'backwards)))
|
||||
(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
|
||||
(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")
|
||||
(let ((mc/enclose-search-term 'words))
|
||||
(mc/mark-previous-like-this arg)))
|
||||
|
||||
;;;###autoload
|
||||
(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")
|
||||
(let ((mc/enclose-search-term 'symbols))
|
||||
(mc/mark-previous-like-this arg)))
|
||||
|
||||
(defun mc/mark-lines (num-lines direction)
|
||||
(dotimes (i (if (= num-lines 0) 1 num-lines))
|
||||
(mc/save-excursion
|
||||
(let ((furthest-cursor (cl-ecase direction
|
||||
(forwards (mc/furthest-cursor-after-point))
|
||||
(backwards (mc/furthest-cursor-before-point)))))
|
||||
(when (overlayp furthest-cursor)
|
||||
(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
|
||||
(defun mc/mark-next-lines (arg)
|
||||
(interactive "p")
|
||||
(mc/mark-lines arg 'forwards)
|
||||
(mc/maybe-multiple-cursors-mode))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-previous-lines (arg)
|
||||
(interactive "p")
|
||||
(mc/mark-lines arg 'backwards)
|
||||
(mc/maybe-multiple-cursors-mode))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/unmark-next-like-this ()
|
||||
"Deselect next part of the buffer matching the currently active region."
|
||||
(interactive)
|
||||
(mc/mark-next-like-this -1))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/unmark-previous-like-this ()
|
||||
"Deselect prev part of the buffer matching the currently active region."
|
||||
(interactive)
|
||||
(mc/mark-previous-like-this -1))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/skip-to-next-like-this ()
|
||||
"Skip the current one and select the next part of the buffer
|
||||
matching the currently active region."
|
||||
(interactive)
|
||||
(mc/mark-next-like-this 0))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/skip-to-previous-like-this ()
|
||||
"Skip the current one and select the prev part of the buffer
|
||||
matching the currently active region."
|
||||
(interactive)
|
||||
(mc/mark-previous-like-this 0))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-all-like-this ()
|
||||
@ -147,7 +371,7 @@ With zero ARG, skip the last one and mark next."
|
||||
(let ((master (point))
|
||||
(case-fold-search nil)
|
||||
(point-first (< (point) (mark)))
|
||||
(re (regexp-opt (mc/region-strings))))
|
||||
(re (regexp-opt (mc/region-strings) mc/enclose-search-term)))
|
||||
(mc/save-excursion
|
||||
(goto-char 0)
|
||||
(while (search-forward-regexp re nil t)
|
||||
@ -158,73 +382,358 @@ With zero ARG, skip the last one and mark next."
|
||||
(when point-first (exchange-point-and-mark)))))
|
||||
(if (> (mc/num-cursors) 1)
|
||||
(multiple-cursors-mode 1)
|
||||
(multiple-cursors-mode 0)))
|
||||
(mc/disable-multiple-cursors-mode)))
|
||||
|
||||
(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
|
||||
(defun mc/mark-all-in-region (beg end)
|
||||
(defun mc/mark-all-words-like-this ()
|
||||
(interactive)
|
||||
(mc--select-thing-at-point-or-bark 'word)
|
||||
(let ((mc/enclose-search-term 'words))
|
||||
(mc/mark-all-like-this)))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-all-symbols-like-this ()
|
||||
(interactive)
|
||||
(mc--select-thing-at-point-or-bark 'symbol)
|
||||
(let ((mc/enclose-search-term 'symbols))
|
||||
(mc/mark-all-like-this)))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-all-in-region (beg end &optional search)
|
||||
"Find and mark all the parts in the region matching the given search"
|
||||
(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))
|
||||
(mc/remove-fake-cursors)
|
||||
(goto-char beg)
|
||||
(while (search-forward search end t)
|
||||
(push-mark (match-beginning 0))
|
||||
(mc/create-fake-cursor-at-point))
|
||||
(let ((first (mc/furthest-cursor-before-point)))
|
||||
(if (not first)
|
||||
(error "Search failed for %S" search)
|
||||
(mc/pop-state-from-overlay first))))
|
||||
(if (> (mc/num-cursors) 1)
|
||||
(multiple-cursors-mode 1)
|
||||
(multiple-cursors-mode 0)))
|
||||
(if (string= search "")
|
||||
(message "Mark aborted")
|
||||
(progn
|
||||
(mc/remove-fake-cursors)
|
||||
(goto-char beg)
|
||||
(let ((lastmatch))
|
||||
(while (search-forward search end t)
|
||||
(push-mark (match-beginning 0))
|
||||
(mc/create-fake-cursor-at-point)
|
||||
(setq lastmatch t))
|
||||
(unless lastmatch
|
||||
(error "Search failed for %S" search)))
|
||||
(goto-char (match-end 0))
|
||||
(if (< (mc/num-cursors) 3)
|
||||
(mc/disable-multiple-cursors-mode)
|
||||
(mc/pop-state-from-overlay (mc/furthest-cursor-before-point))
|
||||
(multiple-cursors-mode 1))))))
|
||||
|
||||
;;;###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)
|
||||
(mc/disable-multiple-cursors-mode)
|
||||
(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))))
|
||||
|
||||
(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)
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-more-like-this-extended ()
|
||||
"Like mark-more-like-this, but then lets you adjust with arrows key.
|
||||
The actual adjustment made depends on the final component of the
|
||||
key-binding used to invoke the command, with all modifiers removed:
|
||||
"Like mark-more-like-this, but then lets you adjust with arrow keys.
|
||||
The adjustments work like this:
|
||||
|
||||
<up> Mark previous like this
|
||||
<down> Mark next like this
|
||||
<left> If last was previous, skip it
|
||||
If last was next, remove it
|
||||
<right> If last was next, skip it
|
||||
If last was previous, remove it
|
||||
<up> Mark previous like this and set direction to \\='up
|
||||
<down> Mark next like this and set direction to \\='down
|
||||
|
||||
Then, continue to read input events and further add or move marks
|
||||
as long as the input event read (with all modifiers removed)
|
||||
is one of the above."
|
||||
If direction is \\='up:
|
||||
|
||||
<left> Skip past the cursor furthest up
|
||||
<right> Remove the cursor furthest up
|
||||
|
||||
If direction is \\='down:
|
||||
|
||||
<left> Remove the cursor furthest down
|
||||
<right> Skip past the cursor furthest down
|
||||
|
||||
The bindings for these commands can be changed.
|
||||
See `mc/mark-more-like-this-extended-keymap'."
|
||||
(interactive)
|
||||
(let ((first t)
|
||||
(ev last-command-event)
|
||||
(cmd 'mc/mark-next-like-this)
|
||||
(arg 1)
|
||||
last echo-keystrokes)
|
||||
(while cmd
|
||||
(let ((base (event-basic-type ev)))
|
||||
(cond ((eq base 'left)
|
||||
(if (eq last 'mc/mark-previous-like-this)
|
||||
(setq cmd last arg 0)
|
||||
(setq cmd 'mc/mark-next-like-this arg -1)))
|
||||
((eq base 'up)
|
||||
(setq cmd 'mc/mark-previous-like-this arg 1))
|
||||
((eq base 'right)
|
||||
(if (eq last 'mc/mark-next-like-this)
|
||||
(setq cmd last arg 0)
|
||||
(setq cmd 'mc/mark-previous-like-this arg -1)))
|
||||
((eq base 'down)
|
||||
(setq cmd 'mc/mark-next-like-this arg 1))
|
||||
(first
|
||||
(setq cmd 'mc/mark-next-like-this arg 1))
|
||||
(t
|
||||
(setq cmd nil))))
|
||||
(when cmd
|
||||
(ignore-errors
|
||||
(funcall cmd arg))
|
||||
(setq first nil last cmd)
|
||||
(setq ev (read-event "Use arrow keys for more marks: "))))
|
||||
(push ev unread-command-events)))
|
||||
(mc/mmlte--down)
|
||||
(set-transient-map mc/mark-more-like-this-extended-keymap t))
|
||||
|
||||
(defvar mc/mark-more-like-this-extended-direction nil
|
||||
"When using mc/mark-more-like-this-extended
|
||||
are we working on the next or previous cursors?")
|
||||
|
||||
(make-variable-buffer-local 'mc/mark-more-like-this-extended)
|
||||
|
||||
(defun mc/mmlte--message ()
|
||||
(if (eq mc/mark-more-like-this-extended-direction 'up)
|
||||
(message "<up> to mark previous, <left> to skip, <right> to remove, <down> to mark next")
|
||||
(message "<down> to mark next, <right> to skip, <left> to remove, <up> to mark previous")))
|
||||
|
||||
(defun mc/mmlte--up ()
|
||||
(interactive)
|
||||
(mc/mark-previous-like-this 1)
|
||||
(setq mc/mark-more-like-this-extended-direction 'up)
|
||||
(mc/mmlte--message))
|
||||
|
||||
(defun mc/mmlte--down ()
|
||||
(interactive)
|
||||
(mc/mark-next-like-this 1)
|
||||
(setq mc/mark-more-like-this-extended-direction 'down)
|
||||
(mc/mmlte--message))
|
||||
|
||||
(defun mc/mmlte--left ()
|
||||
(interactive)
|
||||
(if (eq mc/mark-more-like-this-extended-direction 'down)
|
||||
(mc/unmark-next-like-this)
|
||||
(mc/skip-to-previous-like-this))
|
||||
(mc/mmlte--message))
|
||||
|
||||
(defun mc/mmlte--right ()
|
||||
(interactive)
|
||||
(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--restrict-mark-all-to-symbols nil)
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-all-like-this-dwim (arg)
|
||||
"Tries to guess what you want to mark all of.
|
||||
Can be pressed multiple times to increase selection.
|
||||
|
||||
With prefix, it behaves the same as original `mc/mark-all-like-this'"
|
||||
(interactive "P")
|
||||
(if arg
|
||||
(mc/mark-all-like-this)
|
||||
(if (and (not (use-region-p))
|
||||
(derived-mode-p 'sgml-mode)
|
||||
(mc--on-tag-name-p))
|
||||
(mc/mark-sgml-tag-pair)
|
||||
(let ((before (mc/num-cursors)))
|
||||
(unless (eq last-command 'mc/mark-all-like-this-dwim)
|
||||
(setq mc--restrict-mark-all-to-symbols nil))
|
||||
(unless (use-region-p)
|
||||
(mc--mark-symbol-at-point)
|
||||
(setq mc--restrict-mark-all-to-symbols t))
|
||||
(if mc--restrict-mark-all-to-symbols
|
||||
(mc/mark-all-symbols-like-this-in-defun)
|
||||
(mc/mark-all-like-this-in-defun))
|
||||
(when (<= (mc/num-cursors) before)
|
||||
(if mc--restrict-mark-all-to-symbols
|
||||
(mc/mark-all-symbols-like-this)
|
||||
(mc/mark-all-like-this)))
|
||||
(when (<= (mc/num-cursors) before)
|
||||
(mc/mark-all-like-this))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-all-dwim (arg)
|
||||
"Tries even harder to guess what you want to mark all of.
|
||||
|
||||
If the region is active and spans multiple lines, it will behave
|
||||
as if `mc/mark-all-in-region'. With the prefix ARG, it will call
|
||||
`mc/edit-lines' instead.
|
||||
|
||||
If the region is inactive or on a single line, it will behave like
|
||||
`mc/mark-all-like-this-dwim'."
|
||||
(interactive "P")
|
||||
(if (and (use-region-p)
|
||||
(not (> (mc/num-cursors) 1))
|
||||
(not (= (mc/line-number-at-pos (region-beginning))
|
||||
(mc/line-number-at-pos (region-end)))))
|
||||
(if arg
|
||||
(call-interactively 'mc/edit-lines)
|
||||
(call-interactively 'mc/mark-all-in-region))
|
||||
(progn
|
||||
(setq this-command 'mc/mark-all-like-this-dwim)
|
||||
(mc/mark-all-like-this-dwim arg))))
|
||||
|
||||
(defun mc--in-defun ()
|
||||
(bounds-of-thing-at-point 'defun))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-all-like-this-in-defun ()
|
||||
"Mark all like this in defun."
|
||||
(interactive)
|
||||
(if (mc--in-defun)
|
||||
(save-restriction
|
||||
(widen)
|
||||
(narrow-to-defun)
|
||||
(mc/mark-all-like-this))
|
||||
(mc/mark-all-like-this)))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-all-words-like-this-in-defun ()
|
||||
"Mark all words like this in defun."
|
||||
(interactive)
|
||||
(mc--select-thing-at-point-or-bark 'word)
|
||||
(if (mc--in-defun)
|
||||
(save-restriction
|
||||
(widen)
|
||||
(narrow-to-defun)
|
||||
(mc/mark-all-words-like-this))
|
||||
(mc/mark-all-words-like-this)))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-all-symbols-like-this-in-defun ()
|
||||
"Mark all symbols like this in defun."
|
||||
(interactive)
|
||||
(mc--select-thing-at-point-or-bark 'symbol)
|
||||
(if (mc--in-defun)
|
||||
(save-restriction
|
||||
(widen)
|
||||
(narrow-to-defun)
|
||||
(mc/mark-all-symbols-like-this))
|
||||
(mc/mark-all-symbols-like-this)))
|
||||
|
||||
(defun mc--mark-symbol-at-point ()
|
||||
"Select the symbol under cursor"
|
||||
(interactive)
|
||||
(when (not (use-region-p))
|
||||
(let ((b (bounds-of-thing-at-point 'symbol)))
|
||||
(goto-char (car b))
|
||||
(set-mark (cdr b)))))
|
||||
|
||||
(defun mc--get-nice-sgml-context ()
|
||||
(car
|
||||
(last
|
||||
(progn
|
||||
(when (looking-at "<") (forward-char 1))
|
||||
(when (looking-back ">" 1) (forward-char -1))
|
||||
(sgml-get-context)))))
|
||||
|
||||
(defun mc--on-tag-name-p ()
|
||||
(let* ((context (save-excursion (mc--get-nice-sgml-context)))
|
||||
(tag-name-len (length (aref context 4)))
|
||||
(beg (aref context 2))
|
||||
(end (+ beg tag-name-len (if (eq 'open (aref context 1)) 1 3))))
|
||||
(and context
|
||||
(>= (point) beg)
|
||||
(<= (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
|
||||
(defun mc/mark-sgml-tag-pair ()
|
||||
"Mark the tag we're in and its pair for renaming."
|
||||
(interactive)
|
||||
(when (not (mc--inside-tag-p))
|
||||
(error "Place point inside tag to rename."))
|
||||
(let ((context (mc--get-nice-sgml-context)))
|
||||
(if (looking-at "</")
|
||||
(setq context (car (last (sgml-get-context)))))
|
||||
(goto-char (aref context 2))
|
||||
(let* ((tag-name (aref context 4))
|
||||
(num-chars (length tag-name))
|
||||
(master-start (1+ (point)))
|
||||
(mirror-end (save-excursion
|
||||
(sgml-skip-tag-forward 1)
|
||||
(1- (point)))))
|
||||
(goto-char (- mirror-end num-chars))
|
||||
(set-mark mirror-end)
|
||||
(mc/create-fake-cursor-at-point)
|
||||
(goto-char master-start)
|
||||
(set-mark (+ (point) num-chars))))
|
||||
(mc/maybe-multiple-cursors-mode))
|
||||
|
||||
(defun mc--inside-tag-p ()
|
||||
(save-excursion
|
||||
(not (null (sgml-get-context)))))
|
||||
|
||||
(provide 'mc-mark-more)
|
||||
|
||||
|
22
mc-mark-pop.el
Normal file
22
mc-mark-pop.el
Normal file
@ -0,0 +1,22 @@
|
||||
;;; mc-mark-pop.el --- Pop cursors off of the mark stack -*- lexical-binding: t; -*-
|
||||
|
||||
(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
|
151
mc-separate-operations.el
Normal file
151
mc-separate-operations.el
Normal file
@ -0,0 +1,151 @@
|
||||
;;; mc-separate-operations.el - functions that work differently on each cursor -*- lexical-binding: t; -*-
|
||||
|
||||
;; 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)
|
||||
(mc/disable-multiple-cursors-mode)
|
||||
)
|
||||
(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 column 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
|
File diff suppressed because it is too large
Load Diff
@ -1,2 +0,0 @@
|
||||
(define-package "multiple-cursors" "1.1.2"
|
||||
"Multiple cursors for Emacs.")
|
@ -1,9 +1,12 @@
|
||||
;;; multiple-cursors.el --- An experiment in multiple cursors for emacs.
|
||||
;;; multiple-cursors.el --- Multiple cursors for emacs. -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2012 Magnar Sveen
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||
;; Package-Version: 1.5.0
|
||||
;; Package-Requires: ((cl-lib "0.5"))
|
||||
;; Keywords: editing cursors
|
||||
;; Homepage: https://github.com/magnars/multiple-cursors.el
|
||||
|
||||
;; 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
|
||||
@ -21,114 +24,178 @@
|
||||
;;; Commentary:
|
||||
|
||||
;; 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 though, I've been using it since 2011 with
|
||||
;; great success and much merriment.
|
||||
;;
|
||||
|
||||
;; ## Basic usage
|
||||
;;
|
||||
|
||||
;; Start out with:
|
||||
;;
|
||||
|
||||
;; (require 'multiple-cursors)
|
||||
;;
|
||||
|
||||
;; Then you have to set up your keybindings - multiple-cursors doesn't presume to
|
||||
;; know how you'd like them laid out. Here are some examples:
|
||||
|
||||
;; When you have an active region that spans multiple lines, the following will
|
||||
;; add a cursor to each line:
|
||||
;;
|
||||
|
||||
;; (global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
|
||||
;;
|
||||
|
||||
;; When you want to add multiple cursors not based on continuous lines, but based on
|
||||
;; keywords in the buffer, use:
|
||||
;;
|
||||
|
||||
;; (global-set-key (kbd "C->") 'mc/mark-next-like-this)
|
||||
;; (global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
|
||||
;; (global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)
|
||||
;;
|
||||
|
||||
;; First mark the word, then add more cursors.
|
||||
;;
|
||||
|
||||
;; 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
|
||||
;; insert a newline in multiple-cursors-mode, use `C-j`.
|
||||
|
||||
;; ## Video
|
||||
|
||||
;; You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.com/e13.html).
|
||||
|
||||
;; ## Command overview
|
||||
|
||||
;; ### 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-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-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-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-more-like-this-extended`: Use arrow keys to quickly mark/skip next/previous occurrences.
|
||||
;; - `mc/add-cursor-on-click`: Bind to a mouse event to add cursors by clicking. See tips-section.
|
||||
|
||||
;; ### Mark many occurrences
|
||||
|
||||
;; - `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-symbols-like-this`: Like `mc/mark-all-like-this` but only for whole symbols.
|
||||
;; - `mc/mark-all-in-region`: Prompts for a string to match in the region, adding cursors to all of them.
|
||||
;; - `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-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.
|
||||
|
||||
;; ### Special
|
||||
|
||||
;; - `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/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
|
||||
|
||||
;; - 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
|
||||
;; insert a newline in multiple-cursors-mode, use `C-j`.
|
||||
;;
|
||||
;; - 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`.
|
||||
;;
|
||||
;; ## More commands to play around with
|
||||
;; - Try pressing `mc/mark-next-like-this` with no region selected. It will just add a cursor
|
||||
;; on the next line.
|
||||
;;
|
||||
;; I've set up my key-bindings like so:
|
||||
;; - 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 occurrence
|
||||
;;
|
||||
;; ;; From active region to multiple cursors:
|
||||
;; (global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
|
||||
;; (global-set-key (kbd "C-S-c C-e") 'mc/edit-ends-of-lines)
|
||||
;; (global-set-key (kbd "C-S-c C-a") 'mc/edit-beginnings-of-lines)
|
||||
;; - Try pressing `mc/mark-all-like-this-dwim` on a tagname in html-mode.
|
||||
;;
|
||||
;; When you have an active region that spans multiple lines, the preceeding three
|
||||
;; commands will add one cursor to each line.
|
||||
;; - Notice that the number of cursors active can be seen in the modeline.
|
||||
;;
|
||||
;; ;; Rectangular region mode
|
||||
;; (global-set-key (kbd "H-SPC") 'set-rectangular-region-anchor)
|
||||
;; - 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.
|
||||
;;
|
||||
;; Think of this one as `set-mark` except you're marking a rectangular region. It is
|
||||
;; an exceedingly quick way of adding multiple cursors to multiple lines.
|
||||
;; - 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.
|
||||
;;
|
||||
;; ;; Mark more like this
|
||||
;; (global-set-key (kbd "M-æ") 'mc/mark-all-like-this)
|
||||
;; (global-set-key (kbd "C-å") 'mc/mark-previous-like-this)
|
||||
;; (global-set-key (kbd "C-æ") 'mc/mark-next-like-this)
|
||||
;; (global-set-key (kbd "C-Æ") 'mc/mark-more-like-this-extended)
|
||||
;; (global-set-key (kbd "M-å") 'mc/mark-all-in-region)
|
||||
;;
|
||||
;; Okay, yes, I have a crazy norwegian keyboard. Regardless, these will look at
|
||||
;; whatever you've got selected at the moment, and mark more places like that in
|
||||
;; the buffer.
|
||||
;; - 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).
|
||||
;;
|
||||
;; 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`.
|
||||
|
||||
;; ### 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
|
||||
;;
|
||||
|
||||
;; Multiple-cursors uses two lists of commands to know what to do: the run-once list
|
||||
;; and the run-for-all list. It comes with a set of defaults, but it would be beyond silly
|
||||
;; to try and include all the known Emacs commands.
|
||||
;;
|
||||
|
||||
;; So that's why multiple-cursors occasionally asks what to do about a command. It will
|
||||
;; then remember your choice by saving it in `~/.emacs.d/.mc-lists.el`. You can change
|
||||
;; the location with:
|
||||
;;
|
||||
|
||||
;; (setq mc/list-file "/my/preferred/file")
|
||||
;;
|
||||
;;
|
||||
|
||||
;; ## Known limitations
|
||||
;;
|
||||
|
||||
;; * 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.
|
||||
;; * 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
|
||||
;; need to limit it, you will have to give it a name.
|
||||
;; * Redo might screw with your cursors. Undo works very well.
|
||||
;;
|
||||
;;
|
||||
|
||||
;; ## Contribute
|
||||
;;
|
||||
|
||||
;; Yes, please do. There's a suite of tests, so remember to add tests for your
|
||||
;; specific feature, or I might break it later.
|
||||
;;
|
||||
|
||||
;; You'll find the repo at:
|
||||
;;
|
||||
|
||||
;; https://github.com/magnars/multiple-cursors.el
|
||||
;;
|
||||
|
||||
;; To fetch the test dependencies:
|
||||
;;
|
||||
|
||||
;; $ cd /path/to/multiple-cursors
|
||||
;; $ git submodule update --init
|
||||
;;
|
||||
|
||||
;; Run the tests with:
|
||||
;;
|
||||
|
||||
;; $ ./util/ecukes/ecukes --graphical
|
||||
;;
|
||||
|
||||
;; ## Contributors
|
||||
|
||||
;; * [Takafumi Arakaki](https://github.com/tkf) made .mc-lists.el diff friendly
|
||||
;; * [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
|
||||
;; * [Fuco](https://github.com/Fuco1) added the first version of `mc/mark-all-like-this-dwim`
|
||||
|
||||
;; Thanks!
|
||||
|
||||
;;; Code:
|
||||
|
||||
(defgroup multiple-cursors nil
|
||||
"Multiple cursors for emacs."
|
||||
:group 'editing)
|
||||
|
||||
(require 'mc-edit-lines)
|
||||
(require 'mc-cycle-cursors)
|
||||
(require 'mc-mark-more)
|
||||
(require 'mc-mark-pop)
|
||||
(require 'rectangular-region-mode)
|
||||
(require 'mc-separate-operations)
|
||||
|
||||
(provide 'multiple-cursors)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
;;; rectangular-region-mode.el
|
||||
;;; rectangular-region-mode.el -*- lexical-binding: t; -*-
|
||||
|
||||
;; Copyright (C) 2012 Magnar Sveen
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||
;; 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 "<return>") 'rrm/switch-to-multiple-cursors)
|
||||
|
||||
(defvar rectangular-region-mode nil)
|
||||
|
||||
(defun rrm/keyboard-quit ()
|
||||
"Exit rectangular-region-mode."
|
||||
(interactive)
|
||||
@ -50,8 +52,9 @@
|
||||
(defun set-rectangular-region-anchor ()
|
||||
"Anchors the rectangular region at point.
|
||||
|
||||
Think of this one as `set-mark' except you're marking a rectangular region. It is
|
||||
an exceedingly quick way of adding multiple cursors to multiple lines."
|
||||
Think of this one as `set-mark' except you're marking a
|
||||
rectangular region. It is an exceedingly quick way of adding
|
||||
multiple cursors to multiple lines."
|
||||
(interactive)
|
||||
(set-marker rrm/anchor (point))
|
||||
(push-mark (point))
|
||||
@ -67,27 +70,30 @@ an exceedingly quick way of adding multiple cursors to multiple lines."
|
||||
|
||||
(defun rrm/repaint ()
|
||||
"Start from the anchor and draw a rectangle between it and point."
|
||||
(rrm/remove-rectangular-region-overlays)
|
||||
(let* ((annoying-arrows-mode nil)
|
||||
(point-column (current-column))
|
||||
(point-line (line-number-at-pos))
|
||||
(anchor-column (save-excursion (goto-char rrm/anchor) (current-column)))
|
||||
(anchor-line (save-excursion (goto-char rrm/anchor) (line-number-at-pos)))
|
||||
(left-column (if (< point-column anchor-column) point-column anchor-column))
|
||||
(right-column (if (> point-column anchor-column) point-column anchor-column))
|
||||
(navigation-step (if (< point-line anchor-line) 1 -1)))
|
||||
(move-to-column anchor-column)
|
||||
(set-mark (point))
|
||||
(move-to-column point-column)
|
||||
(mc/save-excursion
|
||||
(while (not (= anchor-line (line-number-at-pos)))
|
||||
(forward-line navigation-step)
|
||||
(move-to-column anchor-column)
|
||||
(when (= anchor-column (current-column))
|
||||
(set-mark (point))
|
||||
(move-to-column point-column)
|
||||
(when (= point-column (current-column))
|
||||
(mc/create-fake-cursor-at-point)))))))
|
||||
(if (not rectangular-region-mode)
|
||||
(remove-hook 'post-command-hook 'rrm/repaint t)
|
||||
;; else
|
||||
(rrm/remove-rectangular-region-overlays)
|
||||
(let* ((annoying-arrows-mode nil)
|
||||
(point-column (current-column))
|
||||
(point-line (mc/line-number-at-pos))
|
||||
(anchor-column (save-excursion (goto-char rrm/anchor) (current-column)))
|
||||
(anchor-line (save-excursion (goto-char rrm/anchor) (mc/line-number-at-pos)))
|
||||
(left-column (if (< point-column anchor-column) point-column anchor-column))
|
||||
(right-column (if (> point-column anchor-column) point-column anchor-column))
|
||||
(navigation-step (if (< point-line anchor-line) 1 -1)))
|
||||
(move-to-column anchor-column)
|
||||
(set-mark (point))
|
||||
(move-to-column point-column)
|
||||
(mc/save-excursion
|
||||
(while (not (= anchor-line (mc/line-number-at-pos)))
|
||||
(forward-line navigation-step)
|
||||
(move-to-column anchor-column)
|
||||
(when (= anchor-column (current-column))
|
||||
(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)
|
||||
"Switch from rectangular-region-mode to multiple-cursors-mode."
|
||||
@ -103,9 +109,12 @@ an exceedingly quick way of adding multiple cursors to multiple lines."
|
||||
(when rectangular-region-mode
|
||||
(rrm/switch-to-multiple-cursors)))
|
||||
|
||||
;;;###autoload
|
||||
(define-minor-mode rectangular-region-mode
|
||||
"A mode for creating a rectangular region to edit"
|
||||
nil " rr" rectangular-region-mode-map
|
||||
:init-value nil
|
||||
:lighter " rr"
|
||||
:keymap rectangular-region-mode-map
|
||||
(if rectangular-region-mode
|
||||
(progn
|
||||
(add-hook 'after-change-functions 'rrm/switch-to-multiple-cursors t t)
|
||||
|
2
run-tests.sh
Executable file
2
run-tests.sh
Executable file
@ -0,0 +1,2 @@
|
||||
#!/bin/sh -e
|
||||
cask exec ecukes "$@" --no-win
|
@ -1,20 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
set_default () {
|
||||
eval "
|
||||
if [ -z \$$1 ]; then
|
||||
$1=$2
|
||||
fi
|
||||
"
|
||||
}
|
||||
|
||||
set_default ECUKES_EMACS "$(which emacs)"
|
||||
|
||||
echo "*** Emacs version ***"
|
||||
echo "ECUKES_EMACS =" $(which $ECUKES_EMACS)
|
||||
$ECUKES_EMACS --version
|
||||
echo
|
||||
|
||||
exec ./util/ecukes/ecukes --graphical
|
@ -1 +0,0 @@
|
||||
Subproject commit b2c449cf01163df3aa41f401b9aeac4887b3177c
|
2544
util/ert.el
2544
util/ert.el
File diff suppressed because it is too large
Load Diff
@ -1 +0,0 @@
|
||||
Subproject commit 62ef75cb51eef76c547d33a81cb2b6b6e384aefc
|
@ -7,13 +7,13 @@ end
|
||||
|
||||
def run_all_tests
|
||||
system('clear')
|
||||
result = run "./util/ecukes/ecukes --graphical"
|
||||
result = run "./run-tests.sh"
|
||||
puts result
|
||||
end
|
||||
|
||||
def run_test(file)
|
||||
system('clear')
|
||||
result = run "./util/ecukes/ecukes --graphical #{file}"
|
||||
result = run "./run-tests.sh #{file} --verbose"
|
||||
puts result
|
||||
end
|
||||
|
Loading…
x
Reference in New Issue
Block a user