mirror of
https://github.com/magnars/multiple-cursors.el.git
synced 2026-05-10 01:18:19 +00:00
Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 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 |
+11
-3
@@ -1,12 +1,20 @@
|
|||||||
language: emacs-lisp
|
language: emacs-lisp
|
||||||
before_install:
|
before_install:
|
||||||
- if [ "$ECUKES_EMACS" = 'emacs-snapshot' ]; then
|
- if [ "$EMACS" = 'emacs-snapshot' ]; then
|
||||||
sudo add-apt-repository -y ppa:cassou/emacs &&
|
sudo add-apt-repository -y ppa:cassou/emacs &&
|
||||||
sudo apt-get update -qq &&
|
sudo apt-get update -qq &&
|
||||||
sudo apt-get install -qq
|
sudo apt-get install -qq
|
||||||
emacs-snapshot-el emacs-snapshot-gtk emacs-snapshot;
|
emacs-snapshot-el emacs-snapshot-gtk emacs-snapshot;
|
||||||
fi
|
fi
|
||||||
|
- if [ "$EMACS" = 'emacs24' ]; then
|
||||||
|
sudo add-apt-repository -y ppa:cassou/emacs &&
|
||||||
|
sudo apt-get update -qq &&
|
||||||
|
sudo apt-get install -qq
|
||||||
|
emacs24 emacs24-el emacs24-common-non-dfsg;
|
||||||
|
fi
|
||||||
env:
|
env:
|
||||||
- ECUKES_EMACS=emacs
|
- EMACS=emacs
|
||||||
|
- EMACS=emacs24
|
||||||
|
- EMACS=emacs-snapshot
|
||||||
script:
|
script:
|
||||||
./run-travis-ci.sh
|
./run-travis-ci.sh
|
||||||
@@ -35,43 +35,56 @@ 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).
|
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:
|
- `mc/mark-next-like-this`: Adds a cursor and region at the next part of the buffer forwards that matches the current region.
|
||||||
(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
|
- `mc/mark-next-word-like-this`: Like `mc/mark-next-like-this` but only for whole words.
|
||||||
(global-set-key (kbd "C-S-c C-e") 'mc/edit-ends-of-lines)
|
- `mc/mark-next-symbol-like-this`: Like `mc/mark-next-like-this` but only for whole symbols.
|
||||||
(global-set-key (kbd "C-S-c C-a") 'mc/edit-beginnings-of-lines)
|
- `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 occurances.
|
||||||
|
|
||||||
When you have an active region that spans multiple lines, the preceeding three
|
### Mark many occurrences
|
||||||
commands will add one cursor to each line.
|
|
||||||
|
|
||||||
;; Rectangular region mode
|
- `mc/mark-all-like-this`: Marks all parts of the buffer that matches the current region.
|
||||||
(global-set-key (kbd "H-SPC") 'set-rectangular-region-anchor)
|
- `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.
|
||||||
|
|
||||||
Think of this one as `set-mark` except you're marking a rectangular region. It is
|
### Special
|
||||||
an exceedingly quick way of adding multiple cursors to multiple lines.
|
|
||||||
|
|
||||||
;; Mark more like this
|
- `set-rectangular-region-anchor`: Think of this one as `set-mark` except you're marking a rectangular region.
|
||||||
(global-set-key (kbd "M-æ") 'mc/mark-all-like-this)
|
- `mc/mark-sgml-tag-pair`: Mark the current opening and closing tag.
|
||||||
(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
|
## Tips and tricks
|
||||||
whatever you've got selected at the moment, and mark more places like that in
|
|
||||||
the buffer.
|
- 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`.
|
||||||
|
|
||||||
|
- 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-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 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
|
BTW, I highly recommend adding `mc/mark-next-like-this` to a key binding that's
|
||||||
right next to the key for `er/expand-region`.
|
right next to the key for `er/expand-region`.
|
||||||
|
|
||||||
## Scrolling
|
|
||||||
|
|
||||||
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`.
|
|
||||||
|
|
||||||
## Unknown commands
|
## Unknown commands
|
||||||
|
|
||||||
Multiple-cursors uses two lists of commands to know what to do: the run-once list
|
Multiple-cursors uses two lists of commands to know what to do: the run-once list
|
||||||
@@ -113,6 +126,14 @@ Run the tests with:
|
|||||||
|
|
||||||
$ ./util/ecukes/ecukes --graphical
|
$ ./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!
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
"""
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
Feature: Mark all do-what-I-mean
|
||||||
|
|
||||||
|
Scenario: Mark symbols in defun
|
||||||
|
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 the end of the word "abc"
|
||||||
|
And I press "M-f"
|
||||||
|
And I press "M-$"
|
||||||
|
And I type "hmm"
|
||||||
|
Then I should see:
|
||||||
|
"""
|
||||||
|
(defun abc (hmm) (message hmm))
|
||||||
|
(defun def (ghi) (message some-other-ghi))
|
||||||
|
"""
|
||||||
|
|
||||||
|
Scenario: Mark all symbols by pressing twice
|
||||||
|
Given I turn on emacs-lisp-mode
|
||||||
|
And I turn on delete-selection-mode
|
||||||
|
And I insert:
|
||||||
|
"""
|
||||||
|
(defun abc (ghi) (message ghi))
|
||||||
|
(defun def (ghi) (message ghi))
|
||||||
|
"""
|
||||||
|
When I go to the end of the word "abc"
|
||||||
|
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 hmm))
|
||||||
|
"""
|
||||||
@@ -94,3 +94,41 @@ Feature: Marking multiple parts of the buffer
|
|||||||
And I type "more"
|
And I type "more"
|
||||||
Then I should have 2 cursors
|
Then I should have 2 cursors
|
||||||
And I should see "Here's more, more and text"
|
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
|
||||||
|
"""
|
||||||
|
|||||||
@@ -119,6 +119,16 @@ Feature: Multiple cursors core
|
|||||||
And I type "!"
|
And I type "!"
|
||||||
Then I should see "This ! contains the word ! twice"
|
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 press "C->"
|
||||||
|
And I press "C-g"
|
||||||
|
And I type "("
|
||||||
|
Then I should see "This (text contains the word (text twice"
|
||||||
|
|
||||||
Scenario: Bound keyboard macros
|
Scenario: Bound keyboard macros
|
||||||
Given I have bound C-! to a keyboard macro that insert "_"
|
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"
|
And I have cursors at "text" in "This text contains the word text twice"
|
||||||
@@ -148,3 +158,17 @@ Feature: Multiple cursors core
|
|||||||
contains
|
contains
|
||||||
twice
|
twice
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
Scenario: Looping forwards around cursors
|
||||||
|
Given I have cursors at "_" in "1_34567_9"
|
||||||
|
And I press "C-v"
|
||||||
|
And I press "C-v"
|
||||||
|
And I press "C-v"
|
||||||
|
Then the cursor should be at point "8"
|
||||||
|
|
||||||
|
Scenario: Looping backwards around cursors
|
||||||
|
Given I have cursors at "_" in "1_34567_9"
|
||||||
|
And I press "M-v"
|
||||||
|
And I press "M-v"
|
||||||
|
Then the cursor should be at point "2"
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,12 @@
|
|||||||
(add-to-list 'load-path multiple-cursors-root-path)
|
(add-to-list 'load-path multiple-cursors-root-path)
|
||||||
(add-to-list 'load-path multiple-cursors-util-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 "espuds" multiple-cursors-util-path))
|
||||||
|
(add-to-list 'load-path (expand-file-name "vendor" multiple-cursors-util-path))
|
||||||
|
|
||||||
(require 'multiple-cursors)
|
(require 'multiple-cursors)
|
||||||
(require 'espuds)
|
(require 'espuds)
|
||||||
(require 'ert)
|
(require 'ert)
|
||||||
|
(require 'wrap-region)
|
||||||
|
|
||||||
(defun mc/save-lists ()) ;; redefine to do nothing when running tests
|
(defun mc/save-lists ()) ;; redefine to do nothing when running tests
|
||||||
|
|
||||||
@@ -21,6 +23,7 @@
|
|||||||
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
|
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
|
||||||
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
|
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
|
||||||
(global-set-key (kbd "M-!") 'mc/mark-all-like-this)
|
(global-set-key (kbd "M-!") 'mc/mark-all-like-this)
|
||||||
|
(global-set-key (kbd "M-$") 'mc/mark-all-like-this-dwim)
|
||||||
(global-set-key (kbd "M-#") 'mc/mark-all-in-region)
|
(global-set-key (kbd "M-#") 'mc/mark-all-in-region)
|
||||||
(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
|
(global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
|
||||||
(global-set-key (kbd "H-SPC") 'set-rectangular-region-anchor)
|
(global-set-key (kbd "H-SPC") 'set-rectangular-region-anchor)
|
||||||
@@ -31,6 +34,7 @@
|
|||||||
(cua-mode 0)
|
(cua-mode 0)
|
||||||
(delete-selection-mode 0)
|
(delete-selection-mode 0)
|
||||||
(subword-mode 0)
|
(subword-mode 0)
|
||||||
|
(wrap-region-mode 0)
|
||||||
(setq set-mark-default-inactive nil)
|
(setq set-mark-default-inactive nil)
|
||||||
(deactivate-mark))
|
(deactivate-mark))
|
||||||
|
|
||||||
|
|||||||
+56
-14
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
(eval-when-compile (require 'cl))
|
(eval-when-compile (require 'cl))
|
||||||
|
|
||||||
(defun mc/next-cursor-after-point ()
|
(defun mc/next-fake-cursor-after-point ()
|
||||||
(let ((pos (point))
|
(let ((pos (point))
|
||||||
(next-pos (point-max))
|
(next-pos (point-max))
|
||||||
next)
|
next)
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
(setq next cursor))))
|
(setq next cursor))))
|
||||||
next))
|
next))
|
||||||
|
|
||||||
(defun mc/prev-cursor-before-point ()
|
(defun mc/prev-fake-cursor-before-point ()
|
||||||
(let ((pos (point))
|
(let ((pos (point))
|
||||||
(prev-pos (point-min))
|
(prev-pos (point-min))
|
||||||
prev)
|
prev)
|
||||||
@@ -54,27 +54,69 @@
|
|||||||
(setq prev cursor))))
|
(setq prev cursor))))
|
||||||
prev))
|
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)
|
||||||
|
(ecase mc/cycle-looping-behaviour
|
||||||
|
(error (error error-message))
|
||||||
|
(warn (message error-message))
|
||||||
|
(continue 'continue)
|
||||||
|
(stop 'stop)))
|
||||||
|
|
||||||
|
(defun mc/first-fake-cursor-after (point)
|
||||||
|
"Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)."
|
||||||
|
(let* ((cursors (mc/all-fake-cursors))
|
||||||
|
(cursors-after-point (remove-if (lambda (cursor)
|
||||||
|
(< (mc/cursor-beg cursor) point))
|
||||||
|
cursors))
|
||||||
|
(cursors-in-order (sort* cursors-after-point '< :key 'mc/cursor-beg)))
|
||||||
|
(first cursors-in-order)))
|
||||||
|
|
||||||
|
(defun mc/last-fake-cursor-before (point)
|
||||||
|
"Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)."
|
||||||
|
(let* ((cursors (mc/all-fake-cursors))
|
||||||
|
(cursors-before-point (remove-if (lambda (cursor)
|
||||||
|
(> (mc/cursor-end cursor) point))
|
||||||
|
cursors))
|
||||||
|
(cursors-in-order (sort* cursors-before-point '> :key 'mc/cursor-end)))
|
||||||
|
(first cursors-in-order)))
|
||||||
|
|
||||||
|
(defun* mc/cycle (next-cursor fallback-cursor loop-message)
|
||||||
|
(when (null next-cursor)
|
||||||
|
(when (eql 'stop (mc/handle-loop-condition loop-message))
|
||||||
|
(return-from mc/cycle nil))
|
||||||
|
(setf next-cursor fallback-cursor))
|
||||||
|
(mc/create-fake-cursor-at-point)
|
||||||
|
(mc/pop-state-from-overlay next-cursor)
|
||||||
|
(recenter))
|
||||||
|
|
||||||
(defun mc/cycle-forward ()
|
(defun mc/cycle-forward ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((next-cursor (mc/next-cursor-after-point)))
|
(mc/cycle (mc/next-fake-cursor-after-point)
|
||||||
(unless next-cursor
|
(mc/first-fake-cursor-after (point-min))
|
||||||
(error "We're already at the last cursor"))
|
"We're already at the last cursor."))
|
||||||
(mc/create-fake-cursor-at-point)
|
|
||||||
(mc/pop-state-from-overlay next-cursor)
|
|
||||||
(recenter)))
|
|
||||||
|
|
||||||
(defun mc/cycle-backward ()
|
(defun mc/cycle-backward ()
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((prev-cursor (mc/prev-cursor-before-point)))
|
(mc/cycle (mc/prev-fake-cursor-before-point)
|
||||||
(unless prev-cursor
|
(mc/last-fake-cursor-before (point-max))
|
||||||
(error "We're already at the first cursor"))
|
"We're already at the last cursor"))
|
||||||
(mc/create-fake-cursor-at-point)
|
|
||||||
(mc/pop-state-from-overlay prev-cursor)
|
|
||||||
(recenter)))
|
|
||||||
|
|
||||||
(define-key mc/keymap (kbd "C-v") 'mc/cycle-forward)
|
(define-key mc/keymap (kbd "C-v") 'mc/cycle-forward)
|
||||||
(define-key mc/keymap (kbd "M-v") 'mc/cycle-backward)
|
(define-key mc/keymap (kbd "M-v") 'mc/cycle-backward)
|
||||||
|
|
||||||
(provide 'mc-cycle-cursors)
|
(provide 'mc-cycle-cursors)
|
||||||
|
|
||||||
|
|
||||||
|
;; Local Variables:
|
||||||
|
;; coding: utf-8
|
||||||
|
;; byte-compile-warnings: (not cl-functions)
|
||||||
|
;; End:
|
||||||
|
|
||||||
;;; mc-cycle-cursors.el ends here
|
;;; mc-cycle-cursors.el ends here
|
||||||
|
|||||||
+244
-45
@@ -28,6 +28,7 @@
|
|||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
(require 'multiple-cursors-core)
|
(require 'multiple-cursors-core)
|
||||||
|
(require 'thingatpt)
|
||||||
|
|
||||||
(defun mc/cursor-end (cursor)
|
(defun mc/cursor-end (cursor)
|
||||||
(if (overlay-get cursor 'mark-active)
|
(if (overlay-get cursor 'mark-active)
|
||||||
@@ -79,34 +80,69 @@
|
|||||||
(mc/cursor-end cursor))))
|
(mc/cursor-end cursor))))
|
||||||
strings))
|
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 (ecase direction
|
||||||
|
(forwards (< (point) (mark)))
|
||||||
|
(backwards (not (< (point) (mark))))))
|
||||||
|
(furthest-cursor (ecase direction
|
||||||
|
(forwards (mc/furthest-cursor-after-point))
|
||||||
|
(backwards (mc/furthest-cursor-before-point))))
|
||||||
|
(start-char (ecase direction
|
||||||
|
(forwards (mc/furthest-region-end))
|
||||||
|
(backwards (mc/first-region-start))))
|
||||||
|
(search-function (ecase direction
|
||||||
|
(forwards 'search-forward-regexp)
|
||||||
|
(backwards 'search-backward-regexp)))
|
||||||
|
(match-point-getter (ecase direction
|
||||||
|
(forwards 'match-beginning)
|
||||||
|
(backwards 'match-end))))
|
||||||
|
(mc/save-excursion
|
||||||
|
(goto-char start-char)
|
||||||
|
(when skip-last
|
||||||
|
(mc/remove-fake-cursor furthest-cursor))
|
||||||
|
(if (funcall search-function re nil t)
|
||||||
|
(progn
|
||||||
|
(push-mark (funcall match-point-getter 0))
|
||||||
|
(when point-out-of-order
|
||||||
|
(exchange-point-and-mark))
|
||||||
|
(mc/create-fake-cursor-at-point))
|
||||||
|
(error "no more matches found.")))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-next-like-this (arg)
|
(defun mc/mark-next-like-this (arg)
|
||||||
"Find and mark the next part of the buffer matching the currently active region
|
"Find and mark the next part of the buffer matching the currently active region
|
||||||
With negative ARG, delete the last one instead.
|
With negative ARG, delete the last one instead.
|
||||||
With zero ARG, skip the last one and mark next."
|
With zero ARG, skip the last one and mark next."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(unless (region-active-p)
|
(if (region-active-p)
|
||||||
(error "Mark a region to match first."))
|
(if (< arg 0)
|
||||||
(when (< arg 0)
|
(mc/remove-fake-cursor (mc/furthest-cursor-after-point))
|
||||||
(mc/remove-fake-cursor (mc/furthest-cursor-after-point)))
|
(mc/mark-more-like-this (= arg 0) 'forwards))
|
||||||
(when (>= arg 0)
|
(mc/mark-lines arg 'forwards))
|
||||||
(let ((case-fold-search nil)
|
(mc/maybe-multiple-cursors-mode))
|
||||||
(point-first (< (point) (mark)))
|
|
||||||
(re (regexp-opt (mc/region-strings)))
|
;;;###autoload
|
||||||
(furthest-cursor (mc/furthest-cursor-after-point)))
|
(defun mc/mark-next-word-like-this (arg)
|
||||||
(mc/save-excursion
|
(interactive "p")
|
||||||
(goto-char (mc/furthest-region-end))
|
(let ((mc/enclose-search-term 'words))
|
||||||
(when (= arg 0)
|
(mc/mark-next-like-this arg)))
|
||||||
(mc/remove-fake-cursor furthest-cursor))
|
|
||||||
(if (search-forward-regexp re nil t)
|
;;;###autoload
|
||||||
(progn
|
(defun mc/mark-next-symbol-like-this (arg)
|
||||||
(push-mark (match-beginning 0))
|
(interactive "p")
|
||||||
(when point-first (exchange-point-and-mark))
|
(let ((mc/enclose-search-term 'symbols))
|
||||||
(mc/create-fake-cursor-at-point))
|
(mc/mark-next-like-this arg)))
|
||||||
(error "no more found forward")))))
|
|
||||||
(if (> (mc/num-cursors) 1)
|
|
||||||
(multiple-cursors-mode 1)
|
|
||||||
(multiple-cursors-mode 0)))
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-previous-like-this (arg)
|
(defun mc/mark-previous-like-this (arg)
|
||||||
@@ -114,28 +150,57 @@ With zero ARG, skip the last one and mark next."
|
|||||||
With negative ARG, delete the last one instead.
|
With negative ARG, delete the last one instead.
|
||||||
With zero ARG, skip the last one and mark next."
|
With zero ARG, skip the last one and mark next."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(unless (region-active-p)
|
(if (region-active-p)
|
||||||
(error "Mark a region to match first."))
|
(if (< arg 0)
|
||||||
(when (< arg 0)
|
(mc/remove-fake-cursor (mc/furthest-cursor-before-point))
|
||||||
(mc/remove-fake-cursor (mc/furthest-cursor-before-point)))
|
(mc/mark-more-like-this (= arg 0) 'backwards))
|
||||||
(when (>= arg 0)
|
(mc/mark-lines arg 'backwards))
|
||||||
(let ((case-fold-search nil)
|
(mc/maybe-multiple-cursors-mode))
|
||||||
(point-first (< (point) (mark)))
|
|
||||||
(re (regexp-opt (mc/region-strings)))
|
;;;###autoload
|
||||||
(furthest-cursor (mc/furthest-cursor-before-point)))
|
(defun mc/mark-previous-word-like-this (arg)
|
||||||
(mc/save-excursion
|
(interactive "p")
|
||||||
(goto-char (mc/first-region-start))
|
(let ((mc/enclose-search-term 'words))
|
||||||
(when (= arg 0)
|
(mc/mark-previous-like-this arg)))
|
||||||
(mc/remove-fake-cursor furthest-cursor))
|
|
||||||
(if (search-backward-regexp re nil t)
|
;;;###autoload
|
||||||
(progn
|
(defun mc/mark-previous-symbol-like-this (arg)
|
||||||
(push-mark (match-end 0))
|
(interactive "p")
|
||||||
(unless point-first (exchange-point-and-mark))
|
(let ((mc/enclose-search-term 'symbols))
|
||||||
(mc/create-fake-cursor-at-point))
|
(mc/mark-previous-like-this arg)))
|
||||||
(error "no more found backward")))))
|
|
||||||
(if (> (mc/num-cursors) 1)
|
(defun mc/mark-lines (num-lines direction)
|
||||||
(multiple-cursors-mode 1)
|
(dotimes (i num-lines)
|
||||||
(multiple-cursors-mode 0)))
|
(mc/create-fake-cursor-at-point)
|
||||||
|
(ecase direction
|
||||||
|
(forwards (loop do (next-line 1 nil)
|
||||||
|
while (mc/all-fake-cursors (point) (1+ (point)))))
|
||||||
|
(backwards (loop do (previous-line 1 nil)
|
||||||
|
while (mc/all-fake-cursors (point) (1+ (point))))))))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/mark-next-lines (arg)
|
||||||
|
(interactive "p")
|
||||||
|
(mc/mark-lines arg 'forwards)
|
||||||
|
(mc/maybe-multiple-cursors-mode))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/mark-previous-lines (arg)
|
||||||
|
(interactive "p")
|
||||||
|
(mc/mark-lines arg 'backwards)
|
||||||
|
(mc/maybe-multiple-cursors-mode))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/unmark-next-like-this (arg)
|
||||||
|
"Deselect next part of the buffer matching the currently active region."
|
||||||
|
(interactive)
|
||||||
|
(mc/mark-next-like-this -1))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/unmark-previous-like-this (arg)
|
||||||
|
"Deselect prev part of the buffer matching the currently active region."
|
||||||
|
(interactive)
|
||||||
|
(mc/mark-previous-like-this -1))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-all-like-this ()
|
(defun mc/mark-all-like-this ()
|
||||||
@@ -147,7 +212,7 @@ With zero ARG, skip the last one and mark next."
|
|||||||
(let ((master (point))
|
(let ((master (point))
|
||||||
(case-fold-search nil)
|
(case-fold-search nil)
|
||||||
(point-first (< (point) (mark)))
|
(point-first (< (point) (mark)))
|
||||||
(re (regexp-opt (mc/region-strings))))
|
(re (regexp-opt (mc/region-strings) mc/enclose-search-term)))
|
||||||
(mc/save-excursion
|
(mc/save-excursion
|
||||||
(goto-char 0)
|
(goto-char 0)
|
||||||
(while (search-forward-regexp re nil t)
|
(while (search-forward-regexp re nil t)
|
||||||
@@ -160,6 +225,18 @@ With zero ARG, skip the last one and mark next."
|
|||||||
(multiple-cursors-mode 1)
|
(multiple-cursors-mode 1)
|
||||||
(multiple-cursors-mode 0)))
|
(multiple-cursors-mode 0)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/mark-all-words-like-this ()
|
||||||
|
(interactive)
|
||||||
|
(let ((mc/enclose-search-term 'words))
|
||||||
|
(mc/mark-all-like-this)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun mc/mark-all-symbols-like-this ()
|
||||||
|
(interactive)
|
||||||
|
(let ((mc/enclose-search-term 'symbols))
|
||||||
|
(mc/mark-all-like-this)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-all-in-region (beg end)
|
(defun mc/mark-all-in-region (beg end)
|
||||||
"Find and mark all the parts in the region matching the given search"
|
"Find and mark all the parts in the region matching the given search"
|
||||||
@@ -226,6 +303,128 @@ is one of the above."
|
|||||||
(setq ev (read-event "Use arrow keys for more marks: "))))
|
(setq ev (read-event "Use arrow keys for more marks: "))))
|
||||||
(push ev unread-command-events)))
|
(push ev unread-command-events)))
|
||||||
|
|
||||||
|
(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 (mc--no-region-and-in-sgmlish-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))))))
|
||||||
|
|
||||||
|
(defun mc--no-region-and-in-sgmlish-mode ()
|
||||||
|
(and (not (use-region-p))
|
||||||
|
(derived-mode-p 'sgml-mode)))
|
||||||
|
|
||||||
|
(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)
|
||||||
|
(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)
|
||||||
|
(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 ">") (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/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)
|
(provide 'mc-mark-more)
|
||||||
|
|
||||||
;;; mc-mark-more.el ends here
|
;;; mc-mark-more.el ends here
|
||||||
|
|||||||
+104
-48
@@ -25,7 +25,7 @@
|
|||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
(eval-when-compile (require 'cl))
|
(require 'cl)
|
||||||
|
|
||||||
(require 'rect)
|
(require 'rect)
|
||||||
|
|
||||||
@@ -49,12 +49,15 @@
|
|||||||
(setq buffer-undo-list ;; otherwise add a function to activate this cursor
|
(setq buffer-undo-list ;; otherwise add a function to activate this cursor
|
||||||
(cons (cons 'apply (cons 'activate-cursor-for-undo (list id))) buffer-undo-list)))))
|
(cons (cons 'apply (cons 'activate-cursor-for-undo (list id))) buffer-undo-list)))))
|
||||||
|
|
||||||
|
(defun mc/all-fake-cursors (&optional start end)
|
||||||
|
(remove-if-not 'mc/fake-cursor-p
|
||||||
|
(overlays-in (or start (point-min))
|
||||||
|
(or end (point-max)))))
|
||||||
|
|
||||||
(defmacro mc/for-each-fake-cursor (&rest forms)
|
(defmacro mc/for-each-fake-cursor (&rest forms)
|
||||||
"Runs the body for each fake cursor, bound to the name cursor"
|
"Runs the body for each fake cursor, bound to the name cursor"
|
||||||
`(mapc #'(lambda (cursor)
|
`(mapc #'(lambda (cursor) ,@forms)
|
||||||
(when (mc/fake-cursor-p cursor)
|
(mc/all-fake-cursors)))
|
||||||
,@forms))
|
|
||||||
(overlays-in (point-min) (point-max))))
|
|
||||||
|
|
||||||
(defmacro mc/save-excursion (&rest forms)
|
(defmacro mc/save-excursion (&rest forms)
|
||||||
"Saves and restores all the state that multiple-cursors cares about."
|
"Saves and restores all the state that multiple-cursors cares about."
|
||||||
@@ -115,6 +118,11 @@ highlights the entire width of the window."
|
|||||||
(overlay-put overlay 'type 'additional-region)
|
(overlay-put overlay 'type 'additional-region)
|
||||||
overlay))
|
overlay))
|
||||||
|
|
||||||
|
(defvar mc/cursor-specific-vars '(autopair-action
|
||||||
|
autopair-wrap-action
|
||||||
|
er/history)
|
||||||
|
"A list of vars that need to be tracked on a per-cursor basis.")
|
||||||
|
|
||||||
(defun mc/store-current-state-in-overlay (o)
|
(defun mc/store-current-state-in-overlay (o)
|
||||||
"Store relevant info about point and mark in the given overlay."
|
"Store relevant info about point and mark in the given overlay."
|
||||||
(overlay-put o 'point (set-marker (make-marker) (point)))
|
(overlay-put o 'point (set-marker (make-marker) (point)))
|
||||||
@@ -125,7 +133,8 @@ highlights the entire width of the window."
|
|||||||
(overlay-put o 'mark-active mark-active)
|
(overlay-put o 'mark-active mark-active)
|
||||||
(overlay-put o 'yank-undo-function yank-undo-function)
|
(overlay-put o 'yank-undo-function yank-undo-function)
|
||||||
(overlay-put o 'kill-ring-yank-pointer kill-ring-yank-pointer)
|
(overlay-put o 'kill-ring-yank-pointer kill-ring-yank-pointer)
|
||||||
(when (boundp 'er/history) (overlay-put o 'er/history er/history))
|
(dolist (var mc/cursor-specific-vars)
|
||||||
|
(when (boundp var) (overlay-put o var (symbol-value var))))
|
||||||
o)
|
o)
|
||||||
|
|
||||||
(defun mc/restore-state-from-overlay (o)
|
(defun mc/restore-state-from-overlay (o)
|
||||||
@@ -138,7 +147,8 @@ highlights the entire width of the window."
|
|||||||
(setq mark-active (overlay-get o 'mark-active))
|
(setq mark-active (overlay-get o 'mark-active))
|
||||||
(setq yank-undo-function (overlay-get o 'yank-undo-function))
|
(setq yank-undo-function (overlay-get o 'yank-undo-function))
|
||||||
(setq kill-ring-yank-pointer (overlay-get o 'kill-ring-yank-pointer))
|
(setq kill-ring-yank-pointer (overlay-get o 'kill-ring-yank-pointer))
|
||||||
(when (boundp 'er/history) (setq er/history (overlay-get o 'er/history))))
|
(dolist (var mc/cursor-specific-vars)
|
||||||
|
(when (boundp var) (set var (overlay-get o var)))))
|
||||||
|
|
||||||
(defun mc/remove-fake-cursor (o)
|
(defun mc/remove-fake-cursor (o)
|
||||||
"Delete overlay with state, including dependent overlays and markers."
|
"Delete overlay with state, including dependent overlays and markers."
|
||||||
@@ -183,6 +193,7 @@ Saves the current state in the overlay to be restored later."
|
|||||||
(run-hooks 'pre-command-hook)
|
(run-hooks 'pre-command-hook)
|
||||||
(unless (eq this-command 'ignore)
|
(unless (eq this-command 'ignore)
|
||||||
(call-interactively cmd))
|
(call-interactively cmd))
|
||||||
|
(run-hooks 'post-command-hook)
|
||||||
(when deactivate-mark (deactivate-mark)))
|
(when deactivate-mark (deactivate-mark)))
|
||||||
|
|
||||||
(defvar mc--executing-command-for-fake-cursor nil)
|
(defvar mc--executing-command-for-fake-cursor nil)
|
||||||
@@ -297,6 +308,13 @@ not be recognized through the command-remapping lookup."
|
|||||||
(message "[mc] problem in `mc/execute-this-command-for-all-cursors': %s"
|
(message "[mc] problem in `mc/execute-this-command-for-all-cursors': %s"
|
||||||
(error-message-string error)))))
|
(error-message-string error)))))
|
||||||
|
|
||||||
|
;; execute-kbd-macro should never be run for fake cursors. The real cursor will
|
||||||
|
;; execute the keyboard macro, resulting in new commands in the command loop,
|
||||||
|
;; and the fake cursors can pick up on those instead.
|
||||||
|
(defadvice execute-kbd-macro (around skip-fake-cursors activate)
|
||||||
|
(unless mc--executing-command-for-fake-cursor
|
||||||
|
ad-do-it))
|
||||||
|
|
||||||
(defun mc/execute-this-command-for-all-cursors-1 ()
|
(defun mc/execute-this-command-for-all-cursors-1 ()
|
||||||
"Used with post-command-hook to execute supported commands for all cursors.
|
"Used with post-command-hook to execute supported commands for all cursors.
|
||||||
|
|
||||||
@@ -308,35 +326,35 @@ Some commands are so unsupported that they are even prevented for
|
|||||||
the original cursor, to inform about the lack of support."
|
the original cursor, to inform about the lack of support."
|
||||||
(unless mc--executing-command-for-fake-cursor
|
(unless mc--executing-command-for-fake-cursor
|
||||||
|
|
||||||
(if (eq 1 (mc/num-cursors)) ;; no fake cursors? disable mc-mode
|
(if (eq 1 (mc/num-cursors)) ;; no fake cursors? disable mc-mode
|
||||||
(multiple-cursors-mode 0)
|
(multiple-cursors-mode 0)
|
||||||
|
|
||||||
(when this-original-command
|
(when this-original-command
|
||||||
(let ((original-command (or mc--this-command
|
(let ((original-command (or mc--this-command
|
||||||
(command-remapping this-original-command)
|
(command-remapping this-original-command)
|
||||||
this-original-command)))
|
this-original-command)))
|
||||||
|
|
||||||
;; skip keyboard macros, since they will generate actual commands that are
|
;; skip keyboard macros, since they will generate actual commands that are
|
||||||
;; also run in the command loop - we'll handle those later instead.
|
;; also run in the command loop - we'll handle those later instead.
|
||||||
(when (functionp original-command)
|
(when (functionp original-command)
|
||||||
|
|
||||||
;; if it's a lambda, we can't know if it's supported or not
|
;; if it's a lambda, we can't know if it's supported or not
|
||||||
;; - so go ahead and assume it's ok, because we're just optimistic like that
|
;; - so go ahead and assume it's ok, because we're just optimistic like that
|
||||||
(if (not (symbolp original-command))
|
(if (not (symbolp original-command))
|
||||||
(mc/execute-command-for-all-fake-cursors original-command)
|
(mc/execute-command-for-all-fake-cursors original-command)
|
||||||
|
|
||||||
;; otherwise it's a symbol, and we can be more thorough
|
;; otherwise it's a symbol, and we can be more thorough
|
||||||
(if (get original-command 'mc--unsupported)
|
(if (get original-command 'mc--unsupported)
|
||||||
(message "%S is not supported with multiple cursors%s"
|
(message "%S is not supported with multiple cursors%s"
|
||||||
original-command
|
original-command
|
||||||
(get original-command 'mc--unsupported))
|
(get original-command 'mc--unsupported))
|
||||||
(when (and original-command
|
(when (and original-command
|
||||||
(not (memq original-command mc--default-cmds-to-run-once))
|
(not (memq original-command mc--default-cmds-to-run-once))
|
||||||
(not (memq original-command mc/cmds-to-run-once))
|
(not (memq original-command mc/cmds-to-run-once))
|
||||||
(or (memq original-command mc--default-cmds-to-run-for-all)
|
(or (memq original-command mc--default-cmds-to-run-for-all)
|
||||||
(memq original-command mc/cmds-to-run-for-all)
|
(memq original-command mc/cmds-to-run-for-all)
|
||||||
(mc/prompt-for-inclusion-in-whitelist original-command)))
|
(mc/prompt-for-inclusion-in-whitelist original-command)))
|
||||||
(mc/execute-command-for-all-fake-cursors original-command))))))))))
|
(mc/execute-command-for-all-fake-cursors original-command))))))))))
|
||||||
|
|
||||||
(defun mc/remove-fake-cursors ()
|
(defun mc/remove-fake-cursors ()
|
||||||
"Remove all fake cursors.
|
"Remove all fake cursors.
|
||||||
@@ -410,9 +428,16 @@ They are temporarily disabled when multiple-cursors are active.")
|
|||||||
(mapc 'mc/enable-minor-mode mc/temporarily-disabled-minor-modes)
|
(mapc 'mc/enable-minor-mode mc/temporarily-disabled-minor-modes)
|
||||||
(setq mc/temporarily-disabled-minor-modes nil))
|
(setq mc/temporarily-disabled-minor-modes nil))
|
||||||
|
|
||||||
|
(defcustom mc/mode-line
|
||||||
|
`(" mc:" (:eval (format ,(propertize "%d" 'face 'font-lock-warning-face)
|
||||||
|
(mc/num-cursors))))
|
||||||
|
"What to display in the mode line while multiple-cursors-mode is active."
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
(put 'mc/mode-line 'risky-local-variable t)
|
||||||
|
|
||||||
(define-minor-mode multiple-cursors-mode
|
(define-minor-mode multiple-cursors-mode
|
||||||
"Mode while multiple cursors are active."
|
"Mode while multiple cursors are active."
|
||||||
nil " mc" mc/keymap
|
nil mc/mode-line mc/keymap
|
||||||
(if multiple-cursors-mode
|
(if multiple-cursors-mode
|
||||||
(progn
|
(progn
|
||||||
(mc/temporarily-disable-unsupported-minor-modes)
|
(mc/temporarily-disable-unsupported-minor-modes)
|
||||||
@@ -429,6 +454,12 @@ They are temporarily disabled when multiple-cursors are active.")
|
|||||||
|
|
||||||
(add-hook 'after-revert-hook #'(lambda () (multiple-cursors-mode 0)))
|
(add-hook 'after-revert-hook #'(lambda () (multiple-cursors-mode 0)))
|
||||||
|
|
||||||
|
(defun mc/maybe-multiple-cursors-mode ()
|
||||||
|
"Enable multiple-cursors-mode if there is more than one currently active cursor."
|
||||||
|
(if (> (mc/num-cursors) 1)
|
||||||
|
(multiple-cursors-mode 1)
|
||||||
|
(multiple-cursors-mode 0)))
|
||||||
|
|
||||||
(defmacro unsupported-cmd (cmd msg)
|
(defmacro unsupported-cmd (cmd msg)
|
||||||
"Adds command to list of unsupported commands and prevents it
|
"Adds command to list of unsupported commands and prevents it
|
||||||
from being executed if in multiple-cursors-mode."
|
from being executed if in multiple-cursors-mode."
|
||||||
@@ -472,6 +503,20 @@ from being executed if in multiple-cursors-mode."
|
|||||||
"The position of the file that keeps track of your preferences
|
"The position of the file that keeps track of your preferences
|
||||||
for running commands with multiple cursors.")
|
for running commands with multiple cursors.")
|
||||||
|
|
||||||
|
(defun mc/dump-list (list-symbol)
|
||||||
|
"Insert (setq 'LIST-SYMBOL LIST-VALUE) to current buffer."
|
||||||
|
(symbol-macrolet ((value (symbol-value list-symbol)))
|
||||||
|
(insert "(setq " (symbol-name list-symbol) "\n"
|
||||||
|
" '(")
|
||||||
|
(newline-and-indent)
|
||||||
|
(set list-symbol
|
||||||
|
(sort value (lambda (x y) (string-lessp (symbol-name x)
|
||||||
|
(symbol-name y)))))
|
||||||
|
(mapc #'(lambda (cmd) (insert (format "%S" cmd)) (newline-and-indent))
|
||||||
|
value)
|
||||||
|
(insert "))")
|
||||||
|
(newline)))
|
||||||
|
|
||||||
(defun mc/save-lists ()
|
(defun mc/save-lists ()
|
||||||
"Saves preferences for running commands with multiple cursors to `mc/list-file'"
|
"Saves preferences for running commands with multiple cursors to `mc/list-file'"
|
||||||
(with-temp-file mc/list-file
|
(with-temp-file mc/list-file
|
||||||
@@ -481,21 +526,9 @@ for running commands with multiple cursors.")
|
|||||||
(insert ";; It keeps track of your preferences for running commands with multiple cursors.")
|
(insert ";; It keeps track of your preferences for running commands with multiple cursors.")
|
||||||
(newline)
|
(newline)
|
||||||
(newline)
|
(newline)
|
||||||
(insert "(setq mc/cmds-to-run-for-all '(")
|
(mc/dump-list 'mc/cmds-to-run-for-all)
|
||||||
(mapc #'(lambda (cmd) (insert (format "%S" cmd)) (newline-and-indent)) mc/cmds-to-run-for-all)
|
|
||||||
(when mc/cmds-to-run-for-all
|
|
||||||
(forward-line -1)
|
|
||||||
(end-of-line))
|
|
||||||
(insert "))")
|
|
||||||
(newline)
|
(newline)
|
||||||
(newline)
|
(mc/dump-list 'mc/cmds-to-run-once)))
|
||||||
(insert "(setq mc/cmds-to-run-once '(")
|
|
||||||
(mapc #'(lambda (cmd) (insert (format "%S" cmd)) (newline-and-indent)) mc/cmds-to-run-once)
|
|
||||||
(when mc/cmds-to-run-once
|
|
||||||
(forward-line -1)
|
|
||||||
(end-of-line))
|
|
||||||
(insert "))")
|
|
||||||
(newline)))
|
|
||||||
|
|
||||||
(defvar mc/cmds-to-run-once nil
|
(defvar mc/cmds-to-run-once nil
|
||||||
"Commands to run only once in multiple-cursors-mode.")
|
"Commands to run only once in multiple-cursors-mode.")
|
||||||
@@ -507,9 +540,20 @@ for running commands with multiple cursors.")
|
|||||||
mc/edit-ends-of-lines
|
mc/edit-ends-of-lines
|
||||||
mc/edit-beginnings-of-lines
|
mc/edit-beginnings-of-lines
|
||||||
mc/mark-next-like-this
|
mc/mark-next-like-this
|
||||||
|
mc/mark-next-word-like-this
|
||||||
|
mc/mark-next-symbol-like-this
|
||||||
mc/mark-previous-like-this
|
mc/mark-previous-like-this
|
||||||
mc/mark-more-like-this-extended
|
mc/mark-previous-word-like-this
|
||||||
|
mc/mark-previous-symbol-like-this
|
||||||
mc/mark-all-like-this
|
mc/mark-all-like-this
|
||||||
|
mc/mark-all-words-like-this
|
||||||
|
mc/mark-all-symbols-like-this
|
||||||
|
mc/mark-more-like-this-extended
|
||||||
|
mc/mark-all-like-this-in-defun
|
||||||
|
mc/mark-all-words-like-this-in-defun
|
||||||
|
mc/mark-all-symbols-like-this-in-defun
|
||||||
|
mc/mark-all-like-this-dwim
|
||||||
|
mc/mark-sgml-tag-pair
|
||||||
mc/cycle-forward
|
mc/cycle-forward
|
||||||
mc/cycle-backward
|
mc/cycle-backward
|
||||||
rrm/switch-to-multiple-cursors
|
rrm/switch-to-multiple-cursors
|
||||||
@@ -534,6 +578,7 @@ for running commands with multiple cursors.")
|
|||||||
describe-function
|
describe-function
|
||||||
describe-bindings
|
describe-bindings
|
||||||
describe-prefix-bindings
|
describe-prefix-bindings
|
||||||
|
view-echo-area-messages
|
||||||
other-window
|
other-window
|
||||||
kill-buffer-and-window
|
kill-buffer-and-window
|
||||||
split-window-right
|
split-window-right
|
||||||
@@ -541,6 +586,8 @@ for running commands with multiple cursors.")
|
|||||||
delete-other-windows
|
delete-other-windows
|
||||||
toggle-window-split
|
toggle-window-split
|
||||||
mwheel-scroll
|
mwheel-scroll
|
||||||
|
scroll-up-command
|
||||||
|
scroll-down-command
|
||||||
mouse-set-point
|
mouse-set-point
|
||||||
mouse-drag-region
|
mouse-drag-region
|
||||||
quit-window
|
quit-window
|
||||||
@@ -594,6 +641,10 @@ for running commands with multiple cursors.")
|
|||||||
backward-delete-char-untabify
|
backward-delete-char-untabify
|
||||||
delete-char delete-forward-char
|
delete-char delete-forward-char
|
||||||
delete-backward-char
|
delete-backward-char
|
||||||
|
c-electric-backspace
|
||||||
|
org-delete-backward-char
|
||||||
|
paredit-backward-delete
|
||||||
|
autopair-backspace
|
||||||
just-one-space
|
just-one-space
|
||||||
zap-to-char
|
zap-to-char
|
||||||
end-of-line
|
end-of-line
|
||||||
@@ -629,4 +680,9 @@ for running commands with multiple cursors.")
|
|||||||
|
|
||||||
(provide 'multiple-cursors-core)
|
(provide 'multiple-cursors-core)
|
||||||
|
|
||||||
|
;; Local Variables:
|
||||||
|
;; coding: utf-8
|
||||||
|
;; byte-compile-warnings: (not cl-functions)
|
||||||
|
;; End:
|
||||||
|
|
||||||
;;; multiple-cursors-core.el ends here
|
;;; multiple-cursors-core.el ends here
|
||||||
|
|||||||
@@ -1,2 +1,2 @@
|
|||||||
(define-package "multiple-cursors" "1.1.3"
|
(define-package "multiple-cursors" "1.1.5"
|
||||||
"Multiple cursors for Emacs.")
|
"Multiple cursors for Emacs.")
|
||||||
|
|||||||
+88
-58
@@ -23,106 +23,136 @@
|
|||||||
;; Multiple cursors for Emacs. This is some pretty crazy functionality, so yes,
|
;; Multiple cursors for Emacs. This is some pretty crazy functionality, so yes,
|
||||||
;; there are kinks. Don't be afraid tho, I've been using it since 2011 with
|
;; there are kinks. Don't be afraid tho, I've been using it since 2011 with
|
||||||
;; great success and much merriment.
|
;; great success and much merriment.
|
||||||
;;
|
|
||||||
;; ## Basic usage
|
;; ## Basic usage
|
||||||
;;
|
|
||||||
;; Start out with:
|
;; Start out with:
|
||||||
;;
|
|
||||||
;; (require 'multiple-cursors)
|
;; (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
|
;; When you have an active region that spans multiple lines, the following will
|
||||||
;; add a cursor to each line:
|
;; add a cursor to each line:
|
||||||
;;
|
|
||||||
;; (global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
|
;; (global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
|
||||||
;;
|
|
||||||
;; When you want to add multiple cursors not based on continuous lines, but based on
|
;; When you want to add multiple cursors not based on continuous lines, but based on
|
||||||
;; keywords in the buffer, use:
|
;; keywords in the buffer, use:
|
||||||
;;
|
|
||||||
;; (global-set-key (kbd "C->") 'mc/mark-next-like-this)
|
;; (global-set-key (kbd "C->") 'mc/mark-next-like-this)
|
||||||
;; (global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
|
;; (global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
|
||||||
;; (global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)
|
;; (global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)
|
||||||
;;
|
|
||||||
;; First mark the word, then add more cursors.
|
;; First mark the word, then add more cursors.
|
||||||
;;
|
|
||||||
;; To get out of multiple-cursors-mode, press `<return>` or `C-g`. The latter will
|
;; To get out of multiple-cursors-mode, press `<return>` or `C-g`. The latter will
|
||||||
;; first disable multiple regions before disabling multiple cursors. If you want to
|
;; first disable multiple regions before disabling multiple cursors. If you want to
|
||||||
;; insert a newline in multiple-cursors-mode, use `C-j`.
|
;; insert a newline in multiple-cursors-mode, use `C-j`.
|
||||||
;;
|
|
||||||
;;
|
;; ## Video
|
||||||
;; ## More commands to play around with
|
|
||||||
;;
|
;; You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.com/e13.html).
|
||||||
;; I've set up my key-bindings like so:
|
|
||||||
;;
|
;; ## Command overview
|
||||||
;; ;; From active region to multiple cursors:
|
|
||||||
;; (global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines)
|
;; ### Mark one more occurrence
|
||||||
;; (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)
|
;; - `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-word-like-this`: Like `mc/mark-next-like-this` but only for whole words.
|
||||||
;; When you have an active region that spans multiple lines, the preceeding three
|
;; - `mc/mark-next-symbol-like-this`: Like `mc/mark-next-like-this` but only for whole symbols.
|
||||||
;; commands will add one cursor to each line.
|
;; - `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.
|
||||||
;; ;; Rectangular region mode
|
;; - `mc/mark-previous-symbol-like-this`: Like `mc/mark-previous-like-this` but only for whole symbols.
|
||||||
;; (global-set-key (kbd "H-SPC") 'set-rectangular-region-anchor)
|
;; - `mc/mark-more-like-this-extended`: Use arrow keys to quickly mark/skip next/previous occurances.
|
||||||
;;
|
|
||||||
;; Think of this one as `set-mark` except you're marking a rectangular region. It is
|
;; ### Mark many occurrences
|
||||||
;; an exceedingly quick way of adding multiple cursors to multiple lines.
|
|
||||||
;;
|
;; - `mc/mark-all-like-this`: Marks all parts of the buffer that matches the current region.
|
||||||
;; ;; Mark more like this
|
;; - `mc/mark-all-words-like-this`: Like `mc/mark-all-like-this` but only for whole words.
|
||||||
;; (global-set-key (kbd "M-æ") 'mc/mark-all-like-this)
|
;; - `mc/mark-all-symbols-like-this`: Like `mc/mark-all-like-this` but only for whole symbols.
|
||||||
;; (global-set-key (kbd "C-å") 'mc/mark-previous-like-this)
|
;; - `mc/mark-all-in-region`: Prompts for a string to match in the region, adding cursors to all of them.
|
||||||
;; (global-set-key (kbd "C-æ") 'mc/mark-next-like-this)
|
;; - `mc/mark-all-like-this-in-defun`: Marks all parts of the current defun that matches the current region.
|
||||||
;; (global-set-key (kbd "C-Æ") 'mc/mark-more-like-this-extended)
|
;; - `mc/mark-all-words-like-this-in-defun`: Like `mc/mark-all-like-this-in-defun` but only for whole words.
|
||||||
;; (global-set-key (kbd "M-å") 'mc/mark-all-in-region)
|
;; - `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.
|
||||||
;; 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
|
;; ### Special
|
||||||
;; the buffer.
|
|
||||||
;;
|
;; - `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.
|
||||||
|
|
||||||
|
;; ## 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`.
|
||||||
|
|
||||||
|
;; - 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-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 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
|
;; BTW, I highly recommend adding `mc/mark-next-like-this` to a key binding that's
|
||||||
;; right next to the key for `er/expand-region`.
|
;; right next to the key for `er/expand-region`.
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; ## Unknown commands
|
;; ## Unknown commands
|
||||||
;;
|
|
||||||
;; Multiple-cursors uses two lists of commands to know what to do: the run-once list
|
;; Multiple-cursors uses two lists of commands to know what to do: the run-once list
|
||||||
;; and the run-for-all list. It comes with a set of defaults, but it would be beyond silly
|
;; 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.
|
;; 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
|
;; 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
|
;; then remember your choice by saving it in `~/.emacs.d/.mc-lists.el`. You can change
|
||||||
;; the location with:
|
;; the location with:
|
||||||
;;
|
|
||||||
;; (setq mc/list-file "/my/preferred/file")
|
;; (setq mc/list-file "/my/preferred/file")
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; ## Known limitations
|
;; ## Known limitations
|
||||||
;;
|
|
||||||
;; * isearch-forward and isearch-backward aren't supported with multiple cursors.
|
;; * isearch-forward and isearch-backward aren't supported with multiple cursors.
|
||||||
;; You should feel free to add a simplified version that can work with it.
|
;; 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.
|
;; * Commands run with `M-x` won't be repeated for all cursors.
|
||||||
;; * All key bindings that refer to lambdas are always run for all cursors. If you
|
;; * All key bindings that refer to lambdas are always run for all cursors. If you
|
||||||
;; need to limit it, you will have to give it a name.
|
;; need to limit it, you will have to give it a name.
|
||||||
;; * Redo might screw with your cursors. Undo works very well.
|
;; * Redo might screw with your cursors. Undo works very well.
|
||||||
;;
|
|
||||||
;;
|
|
||||||
;; ## Contribute
|
;; ## Contribute
|
||||||
;;
|
|
||||||
;; Yes, please do. There's a suite of tests, so remember to add tests for your
|
;; Yes, please do. There's a suite of tests, so remember to add tests for your
|
||||||
;; specific feature, or I might break it later.
|
;; specific feature, or I might break it later.
|
||||||
;;
|
|
||||||
;; You'll find the repo at:
|
;; You'll find the repo at:
|
||||||
;;
|
|
||||||
;; https://github.com/magnars/multiple-cursors.el
|
;; https://github.com/magnars/multiple-cursors.el
|
||||||
;;
|
|
||||||
;; To fetch the test dependencies:
|
;; To fetch the test dependencies:
|
||||||
;;
|
|
||||||
;; $ cd /path/to/multiple-cursors
|
;; $ cd /path/to/multiple-cursors
|
||||||
;; $ git submodule update --init
|
;; $ git submodule update --init
|
||||||
;;
|
|
||||||
;; Run the tests with:
|
;; Run the tests with:
|
||||||
;;
|
|
||||||
;; $ ./util/ecukes/ecukes --graphical
|
;; $ ./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:
|
;;; Code:
|
||||||
|
|
||||||
(require 'mc-edit-lines)
|
(require 'mc-edit-lines)
|
||||||
|
|||||||
+4
-12
@@ -1,20 +1,12 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh -e
|
||||||
|
|
||||||
cd "$(dirname "$0")"
|
cd "$(dirname "$0")"
|
||||||
|
|
||||||
set_default () {
|
ECUKES_EMACS=${ECUKES_EMACS:-$(which emacs)}
|
||||||
eval "
|
|
||||||
if [ -z \$$1 ]; then
|
|
||||||
$1=$2
|
|
||||||
fi
|
|
||||||
"
|
|
||||||
}
|
|
||||||
|
|
||||||
set_default ECUKES_EMACS "$(which emacs)"
|
|
||||||
|
|
||||||
echo "*** Emacs version ***"
|
echo "*** Emacs version ***"
|
||||||
echo "ECUKES_EMACS =" $(which $ECUKES_EMACS)
|
echo "ECUKES_EMACS = $ECUKES_EMACS"
|
||||||
$ECUKES_EMACS --version
|
"$ECUKES_EMACS" --version
|
||||||
echo
|
echo
|
||||||
|
|
||||||
exec ./util/ecukes/ecukes --graphical
|
exec ./util/ecukes/ecukes --graphical
|
||||||
|
|||||||
Vendored
+329
@@ -0,0 +1,329 @@
|
|||||||
|
;;; wrap-region.el --- Wrap text with punctation or tag
|
||||||
|
|
||||||
|
;; Copyright (C) 2008-2012 Johan Andersson
|
||||||
|
|
||||||
|
;; Author: Johan Andersson <johan.rejeep@gmail.com>
|
||||||
|
;; Maintainer: Johan Andersson <johan.rejeep@gmail.com>
|
||||||
|
;; Version: 0.6.0
|
||||||
|
;; Keywords: speed, convenience
|
||||||
|
;; URL: http://github.com/rejeep/wrap-region
|
||||||
|
|
||||||
|
;; This file is NOT part of GNU Emacs.
|
||||||
|
|
||||||
|
|
||||||
|
;;; License:
|
||||||
|
|
||||||
|
;; This program is free software; you can redistribute it and/or modify
|
||||||
|
;; it under the terms of the GNU General Public License as published by
|
||||||
|
;; the Free Software Foundation; either version 3, or (at your option)
|
||||||
|
;; any later version.
|
||||||
|
|
||||||
|
;; This program is distributed in the hope that it will be useful,
|
||||||
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
;; GNU General Public License for more details.
|
||||||
|
|
||||||
|
;; You should have received a copy of the GNU General Public License
|
||||||
|
;; along with GNU Emacs; see the file COPYING. If not, write to the
|
||||||
|
;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||||
|
;; Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
|
||||||
|
;; wrap-region is a minor mode that wraps a region with
|
||||||
|
;; punctuations. For tagged markup modes, such as HTML and XML, it
|
||||||
|
;; wraps with tags.
|
||||||
|
;;
|
||||||
|
;; To use wrap-region, make sure that this file is in Emacs load-path:
|
||||||
|
;; (add-to-list 'load-path "/path/to/directory/or/file")
|
||||||
|
;;
|
||||||
|
;; Then require wrap-region:
|
||||||
|
;; (require 'wrap-region)
|
||||||
|
|
||||||
|
;; To start wrap-region:
|
||||||
|
;; (wrap-region-mode t) or M-x wrap-region-mode
|
||||||
|
;;
|
||||||
|
;; If you only want wrap-region active in some mode, use hooks:
|
||||||
|
;; (add-hook 'ruby-mode-hook 'wrap-region-mode)
|
||||||
|
;;
|
||||||
|
;; Or if you want to activate it in all buffers, use the global mode:
|
||||||
|
;; (wrap-region-global-mode t)
|
||||||
|
|
||||||
|
;; To wrap a region, select that region and hit one of the punctuation
|
||||||
|
;; keys. In "tag-modes"" (see `wrap-region-tag-active-modes'), "<" is
|
||||||
|
;; replaced and wraps the region with a tag. To activate this behavior
|
||||||
|
;; in a mode that is not default:
|
||||||
|
;; (add-to-list 'wrap-region-tag-active-modes 'some-tag-mode)
|
||||||
|
;;
|
||||||
|
;; `wrap-region-table' contains the default punctuations
|
||||||
|
;; that wraps. You can add and remove new wrappers by using the
|
||||||
|
;; functions `wrap-region-add-wrapper' and
|
||||||
|
;; `wrap-region-remove-wrapper' respectively.
|
||||||
|
;; (wrap-region-add-wrapper "`" "'") ; hit ` then region -> `region'
|
||||||
|
;; (wrap-region-add-wrapper "/*" "*/" "/") ; hit / then region -> /*region*/
|
||||||
|
;; (wrap-region-add-wrapper "$" "$" nil 'latex-mode) ; hit $ then region -> $region$ in latex-mode
|
||||||
|
;; (wrap-region-remove-wrapper "(")
|
||||||
|
;; (wrap-region-remove-wrapper "$" 'latex-mode)
|
||||||
|
;;
|
||||||
|
;; Some modes may have conflicting key bindings with wrap-region. To
|
||||||
|
;; avoid conflicts, the list `wrap-region-except-modes' contains names
|
||||||
|
;; of modes where wrap-region should not be activated (note, only in
|
||||||
|
;; the global mode). You can add new modes like this:
|
||||||
|
;; (add-to-list 'wrap-region-except-modes 'conflicting-mode)
|
||||||
|
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
|
||||||
|
(require 'edmacro)
|
||||||
|
(eval-when-compile
|
||||||
|
(require 'cl))
|
||||||
|
|
||||||
|
|
||||||
|
(defstruct wrap-region-wrapper key left right modes)
|
||||||
|
|
||||||
|
(defvar wrap-region-mode-map (make-sparse-keymap)
|
||||||
|
"Keymap for `wrap-region-mode'.")
|
||||||
|
|
||||||
|
(defvar wrap-region-table (make-hash-table :test 'equal)
|
||||||
|
"Table with wrapper pairs.")
|
||||||
|
|
||||||
|
(defvar wrap-region-tag-active-modes '(html-mode sgml-mode rhtml-mode nxml-mode nxhtml-mode)
|
||||||
|
"List of modes that uses tags.")
|
||||||
|
|
||||||
|
(defvar wrap-region-except-modes '(calc-mode dired-mode)
|
||||||
|
"A list of modes in which `wrap-region-mode' should not be activated.")
|
||||||
|
|
||||||
|
(defvar wrap-region-hook nil
|
||||||
|
"Called when `wrap-region-mode' is turned on.")
|
||||||
|
|
||||||
|
(defvar wrap-region-before-wrap-hook nil
|
||||||
|
"Called before wrapping.")
|
||||||
|
|
||||||
|
(defvar wrap-region-after-wrap-hook nil
|
||||||
|
"Called after wrapping.")
|
||||||
|
|
||||||
|
(defvar wrap-region-only-with-negative-prefix nil
|
||||||
|
"Only wrap if the trigger key is prefixed with a negative value.")
|
||||||
|
|
||||||
|
(defvar wrap-region-keep-mark nil
|
||||||
|
"Keep the wrapped region active.")
|
||||||
|
|
||||||
|
(defun wrap-region-trigger (arg key)
|
||||||
|
"Called when trigger key is pressed."
|
||||||
|
(let* ((wrapper (wrap-region-find key)))
|
||||||
|
(if (and wrapper
|
||||||
|
(region-active-p)
|
||||||
|
(if wrap-region-only-with-negative-prefix (< arg 0) t))
|
||||||
|
(if (wrap-region-insert-tag-p key)
|
||||||
|
(wrap-region-with-tag)
|
||||||
|
(wrap-region-with-punctuations
|
||||||
|
(wrap-region-wrapper-left wrapper)
|
||||||
|
(wrap-region-wrapper-right wrapper)))
|
||||||
|
(wrap-region-fallback key))))
|
||||||
|
|
||||||
|
(defun wrap-region-find (key)
|
||||||
|
"Find first wrapper with trigger KEY that should be active in MAJOR-MODE."
|
||||||
|
(let ((wrappers (gethash key wrap-region-table)))
|
||||||
|
(or
|
||||||
|
(find-if
|
||||||
|
(lambda (wrapper)
|
||||||
|
(member major-mode (wrap-region-wrapper-modes wrapper)))
|
||||||
|
wrappers)
|
||||||
|
(find-if
|
||||||
|
(lambda (wrapper)
|
||||||
|
(not (wrap-region-wrapper-modes wrapper)))
|
||||||
|
wrappers))))
|
||||||
|
|
||||||
|
(defun wrap-region-insert-tag-p (key)
|
||||||
|
"Check if tag should be inserted or not."
|
||||||
|
(and
|
||||||
|
(equal key "<")
|
||||||
|
(member major-mode wrap-region-tag-active-modes)))
|
||||||
|
|
||||||
|
(defun wrap-region-with-tag ()
|
||||||
|
"Wraps region with tag."
|
||||||
|
(let* ((tag (read-string "Enter Tag (with optional attributes): "))
|
||||||
|
(split (split-string tag " "))
|
||||||
|
(tag-name (car split))
|
||||||
|
(left (concat "<" tag ">"))
|
||||||
|
(right (concat "</" tag-name ">")))
|
||||||
|
(wrap-region-with left right)))
|
||||||
|
|
||||||
|
(defun wrap-region-with-punctuations (left right)
|
||||||
|
"Wraps region with LEFT and RIGHT punctuations."
|
||||||
|
(wrap-region-with left right))
|
||||||
|
|
||||||
|
(defun wrap-region-with (left right)
|
||||||
|
"Wraps region with LEFT and RIGHT."
|
||||||
|
(run-hooks 'wrap-region-before-wrap-hook)
|
||||||
|
(let ((beg (region-beginning))
|
||||||
|
(end (region-end))
|
||||||
|
(pos (point))
|
||||||
|
(deactivate-mark nil))
|
||||||
|
(save-excursion
|
||||||
|
(goto-char beg)
|
||||||
|
(insert left)
|
||||||
|
(goto-char (+ end (length left)))
|
||||||
|
(insert right))
|
||||||
|
(if wrap-region-keep-mark
|
||||||
|
(let* ((beg-p (eq beg pos))
|
||||||
|
(beg* (+ beg (length left)))
|
||||||
|
(end* (+ end (length left)))
|
||||||
|
(pos* (if beg-p beg* end*)))
|
||||||
|
(push-mark (if beg-p end* beg*) nil t)
|
||||||
|
(goto-char (if beg-p beg* end*)))
|
||||||
|
(deactivate-mark)))
|
||||||
|
(run-hooks 'wrap-region-after-wrap-hook))
|
||||||
|
|
||||||
|
(defun wrap-region-fallback (key)
|
||||||
|
"Execute function that KEY was bound to before `wrap-region-mode'."
|
||||||
|
(let ((wrap-region-mode nil))
|
||||||
|
(execute-kbd-macro
|
||||||
|
(edmacro-parse-keys key))))
|
||||||
|
|
||||||
|
(defun wrap-region-add-wrappers (wrappers)
|
||||||
|
"Add WRAPPERS by calling `wrap-region-add-wrapper' for each one."
|
||||||
|
(mapc
|
||||||
|
(lambda (wrapper)
|
||||||
|
(apply 'wrap-region-add-wrapper wrapper))
|
||||||
|
wrappers))
|
||||||
|
|
||||||
|
(defun wrap-region-add-wrapper (left right &optional key mode-or-modes)
|
||||||
|
"Add new LEFT and RIGHT wrapper.
|
||||||
|
|
||||||
|
Optional KEY is the trigger key and MODE-OR-MODES is a single
|
||||||
|
mode or multiple modes that the wrapper should trigger in."
|
||||||
|
(or key (setq key left))
|
||||||
|
(let ((wrappers (gethash key wrap-region-table))
|
||||||
|
(modes
|
||||||
|
(if mode-or-modes
|
||||||
|
(if (listp mode-or-modes)
|
||||||
|
mode-or-modes
|
||||||
|
(list mode-or-modes)))))
|
||||||
|
(if wrappers
|
||||||
|
(let ((wrapper-exactly-same
|
||||||
|
(find-if
|
||||||
|
(lambda (wrapper)
|
||||||
|
(and
|
||||||
|
(equal (wrap-region-wrapper-key wrapper) key)
|
||||||
|
(equal (wrap-region-wrapper-left wrapper) left)
|
||||||
|
(equal (wrap-region-wrapper-right wrapper) right)))
|
||||||
|
wrappers)))
|
||||||
|
(if wrapper-exactly-same
|
||||||
|
(when (wrap-region-wrapper-modes wrapper-exactly-same)
|
||||||
|
(if modes
|
||||||
|
(setf
|
||||||
|
(wrap-region-wrapper-modes wrapper-exactly-same)
|
||||||
|
(union modes (wrap-region-wrapper-modes wrapper-exactly-same)))
|
||||||
|
(let ((new-wrapper (make-wrap-region-wrapper :key key :left left :right right)))
|
||||||
|
(puthash key (cons new-wrapper wrappers) wrap-region-table))))
|
||||||
|
(let* ((new-wrapper (make-wrap-region-wrapper :key key :left left :right right :modes modes))
|
||||||
|
(wrapper-same-trigger
|
||||||
|
(find-if
|
||||||
|
(lambda (wrapper)
|
||||||
|
(equal (wrap-region-wrapper-key wrapper) key))
|
||||||
|
wrappers))
|
||||||
|
(wrapper-same-trigger-modes
|
||||||
|
(wrap-region-wrapper-modes wrapper-same-trigger)))
|
||||||
|
(when (and wrapper-same-trigger wrapper-same-trigger-modes)
|
||||||
|
(let ((new-modes (nset-difference (wrap-region-wrapper-modes wrapper-same-trigger) modes)))
|
||||||
|
(if new-modes
|
||||||
|
(setf (wrap-region-wrapper-modes wrapper-same-trigger) new-modes)
|
||||||
|
(setq wrappers (delete wrapper-same-trigger wrappers)))))
|
||||||
|
(puthash key (cons new-wrapper wrappers) wrap-region-table))))
|
||||||
|
(let ((new-wrapper (make-wrap-region-wrapper :key key :left left :right right :modes modes)))
|
||||||
|
(puthash key (list new-wrapper) wrap-region-table))))
|
||||||
|
(wrap-region-define-trigger key))
|
||||||
|
|
||||||
|
(defun wrap-region-remove-wrapper (key &optional mode-or-modes)
|
||||||
|
"Remove wrapper with trigger KEY or exclude from MODE-OR-MODES.
|
||||||
|
|
||||||
|
If MODE-OR-MODES is not present, all wrappers for KEY are removed."
|
||||||
|
(if mode-or-modes
|
||||||
|
(let ((wrappers (gethash key wrap-region-table))
|
||||||
|
(modes
|
||||||
|
(if mode-or-modes
|
||||||
|
(if (listp mode-or-modes)
|
||||||
|
mode-or-modes
|
||||||
|
(list mode-or-modes)))))
|
||||||
|
(mapc
|
||||||
|
(lambda (mode)
|
||||||
|
(let ((wrapper-including-mode
|
||||||
|
(find-if
|
||||||
|
(lambda (wrapper)
|
||||||
|
(member mode (wrap-region-wrapper-modes wrapper)))
|
||||||
|
wrappers)))
|
||||||
|
(when wrapper-including-mode
|
||||||
|
(let ((new-modes (delete mode (wrap-region-wrapper-modes wrapper-including-mode))))
|
||||||
|
(if new-modes
|
||||||
|
(setf (wrap-region-wrapper-modes wrapper-including-mode) new-modes)
|
||||||
|
(puthash key (delete wrapper-including-mode wrappers) wrap-region-table))))))
|
||||||
|
modes))
|
||||||
|
(wrap-region-destroy-wrapper key)))
|
||||||
|
|
||||||
|
(defun wrap-region-destroy-wrapper (key)
|
||||||
|
"Remove the wrapper bound to KEY, no questions asked."
|
||||||
|
(remhash key wrap-region-table)
|
||||||
|
(wrap-region-unset-key key))
|
||||||
|
|
||||||
|
(defun wrap-region-define-wrappers ()
|
||||||
|
"Defines defaults wrappers."
|
||||||
|
(mapc
|
||||||
|
(lambda (pair)
|
||||||
|
(apply 'wrap-region-add-wrapper pair))
|
||||||
|
'(("\"" "\"")
|
||||||
|
("'" "'")
|
||||||
|
("(" ")")
|
||||||
|
("{" "}")
|
||||||
|
("[" "]")
|
||||||
|
("<" ">"))))
|
||||||
|
|
||||||
|
(defun wrap-region-define-trigger (key)
|
||||||
|
"Defines KEY as wrapper."
|
||||||
|
(wrap-region-define-key
|
||||||
|
key
|
||||||
|
`(lambda (arg)
|
||||||
|
(interactive "p")
|
||||||
|
(wrap-region-trigger arg ,key))))
|
||||||
|
|
||||||
|
(defun wrap-region-unset-key (key)
|
||||||
|
"Remove KEY from `wrap-region-mode-map'."
|
||||||
|
(wrap-region-define-key key))
|
||||||
|
|
||||||
|
(defun wrap-region-define-key (key &optional fn)
|
||||||
|
"Binds KEY to FN in `wrap-region-mode-map'."
|
||||||
|
(define-key wrap-region-mode-map (read-kbd-macro key) fn))
|
||||||
|
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(define-minor-mode wrap-region-mode
|
||||||
|
"Wrap region with stuff."
|
||||||
|
:init-value nil
|
||||||
|
:lighter " wr"
|
||||||
|
:keymap wrap-region-mode-map
|
||||||
|
(when wrap-region-mode
|
||||||
|
(wrap-region-define-wrappers)
|
||||||
|
(run-hooks 'wrap-region-hook)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun turn-on-wrap-region-mode ()
|
||||||
|
"Turn on `wrap-region-mode'"
|
||||||
|
(interactive)
|
||||||
|
(unless (member major-mode wrap-region-except-modes)
|
||||||
|
(wrap-region-mode +1)))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(defun turn-off-wrap-region-mode ()
|
||||||
|
"Turn off `wrap-region-mode'."
|
||||||
|
(interactive)
|
||||||
|
(wrap-region-mode -1))
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(define-globalized-minor-mode wrap-region-global-mode
|
||||||
|
wrap-region-mode
|
||||||
|
turn-on-wrap-region-mode)
|
||||||
|
|
||||||
|
(provide 'wrap-region)
|
||||||
|
|
||||||
|
;;; wrap-region.el ends here
|
||||||
Reference in New Issue
Block a user