mirror of
https://github.com/magnars/multiple-cursors.el.git
synced 2026-05-10 09:28:18 +00:00
Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| ddd677091a | |||
| 2cd802b1f7 | |||
| 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 |
@@ -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'
|
||||||
@@ -1,3 +1,7 @@
|
|||||||
elpa
|
elpa
|
||||||
*.elc
|
*.elc
|
||||||
/.ecukes-failing-scenarios
|
/.ecukes-failing-scenarios
|
||||||
|
|
||||||
|
# ELPA-generated files
|
||||||
|
/multiple-cursors-pkg.el
|
||||||
|
/multiple-cursors-autoloads.el
|
||||||
|
|||||||
-21
@@ -1,21 +0,0 @@
|
|||||||
language: emacs-lisp
|
|
||||||
before_install:
|
|
||||||
- if [ "$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
|
|
||||||
- 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
|
|
||||||
- curl -fsSkL https://raw.github.com/cask/cask/master/go | python
|
|
||||||
- export PATH="/home/travis/.cask/bin:$PATH"
|
|
||||||
- cask
|
|
||||||
env:
|
|
||||||
- EMACS=emacs24 TAGS=""
|
|
||||||
script:
|
|
||||||
./run-travis-ci.sh
|
|
||||||
@@ -1,14 +1,38 @@
|
|||||||
# 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,
|
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.
|
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
|
## Installation
|
||||||
|
|
||||||
I highly recommend installing multiple-cursors through `package.el`.
|
I highly recommend installing multiple-cursors through `package.el`.
|
||||||
|
|
||||||
It's available on [MELPA](http://melpa.org/) and [MELPA Stable](http://stable.melpa.org):
|
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
|
M-x package-install multiple-cursors
|
||||||
|
|
||||||
@@ -43,10 +67,6 @@ To get out of multiple-cursors-mode, press `<return>` or `C-g`. The latter will
|
|||||||
first disable multiple regions before disabling multiple cursors. If you want to
|
first disable multiple regions before disabling multiple cursors. If you want to
|
||||||
insert a newline in multiple-cursors-mode, use `C-j`.
|
insert a newline in multiple-cursors-mode, use `C-j`.
|
||||||
|
|
||||||
## Important note
|
|
||||||
|
|
||||||
Multiple cursors does not do well when you invoke its commands with `M-x`. It needs to be bound to keys to work properly. Pull request to fix this is welcome.
|
|
||||||
|
|
||||||
## Video
|
## Video
|
||||||
|
|
||||||
You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.com/e13.html).
|
You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.com/e13.html).
|
||||||
@@ -55,49 +75,59 @@ You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.co
|
|||||||
|
|
||||||
### Mark one more occurrence
|
### Mark one more occurrence
|
||||||
|
|
||||||
- `mc/mark-next-like-this`: Adds a cursor and region at the next part of the buffer forwards that matches the current region.
|
| Command | Description |
|
||||||
- `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-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.
|
| `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-symbol-like-this`: Like `mc/mark-next-like-this` but only for whole symbols.
|
| `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-previous-like-this`: Adds a cursor and region at the next part of the buffer backwards that matches the current region.
|
| `mc/mark-next-word-like-this` | Like `mc/mark-next-like-this` but only for whole words. |
|
||||||
- `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-next-symbol-like-this` | Like `mc/mark-next-like-this` but only for whole symbols. |
|
||||||
- `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-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-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-symbol-like-this`: Like `mc/mark-previous-like-this` but only for whole symbols.
|
| `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-more-like-this-extended`: Use arrow keys to quickly mark/skip next/previous occurances.
|
| `mc/mark-previous-word-like-this` | Like `mc/mark-previous-like-this` but only for whole words. |
|
||||||
- `mc/add-cursor-on-click`: Bind to a mouse event to add cursors by clicking. See tips-section.
|
| `mc/mark-previous-symbol-like-this` | Like `mc/mark-previous-like-this` but only for whole symbols. |
|
||||||
- `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.
|
| `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. |
|
||||||
|
|
||||||
### Juggle around with the current cursors
|
### Juggle around with the current cursors
|
||||||
|
|
||||||
- `mc/unmark-next-like-this`: Remove the cursor furthest down in the buffer.
|
| Command | Description |
|
||||||
- `mc/unmark-previous-like-this`: Remove the cursor furthest up in the buffer.
|
|---------------------------------|--------------------------------------------------------------------|
|
||||||
- `mc/skip-to-next-like-this`: Remove the cursor furthest down, marking the next occurance down.
|
| `mc/unmark-next-like-this` | Remove the cursor furthest down in the buffer. |
|
||||||
- `mc/skip-to-previous-like-this`: Remove the cursor furthest up, marking the next occurance up.
|
| `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. |
|
||||||
|
|
||||||
### Mark many occurrences
|
### Mark many occurrences
|
||||||
|
|
||||||
- `mc/edit-lines`: Adds one cursor to each line in the current region.
|
| Command | Description |
|
||||||
- `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/edit-lines` | Adds one cursor to each line in the current region. |
|
||||||
- `mc/mark-all-like-this`: Marks all parts of the buffer that matches the current region.
|
| `mc/edit-beginnings-of-lines` | Adds a cursor at the start of each line in the current region. |
|
||||||
- `mc/mark-all-words-like-this`: Like `mc/mark-all-like-this` but only for whole words.
|
| `mc/edit-ends-of-lines` | Adds a cursor at the end of each line in the current region. |
|
||||||
- `mc/mark-all-symbols-like-this`: Like `mc/mark-all-like-this` but only for whole symbols.
|
| `mc/mark-all-like-this` | Marks all parts of the buffer that matches the current region. |
|
||||||
- `mc/mark-all-in-region`: Prompts for a string to match in the region, adding cursors to all of them.
|
| `mc/mark-all-words-like-this` | Like `mc/mark-all-like-this` but only for whole words. |
|
||||||
- `mc/mark-all-like-this-in-defun`: Marks all parts of the current defun that matches the current region.
|
| `mc/mark-all-symbols-like-this` | Like `mc/mark-all-like-this` but only for whole symbols. |
|
||||||
- `mc/mark-all-words-like-this-in-defun`: Like `mc/mark-all-like-this-in-defun` but only for whole words.
|
| `mc/mark-all-in-region` | Prompts for a string to match in the region, adding cursors to all of them. |
|
||||||
- `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-in-defun` | Marks all parts of the current defun that matches the current region. |
|
||||||
- `mc/mark-all-dwim`: Tries to be smart about marking everything you want. Can be pressed multiple times.
|
| `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. |
|
||||||
|
|
||||||
### Special
|
### Special
|
||||||
|
|
||||||
- `set-rectangular-region-anchor`: Think of this one as `set-mark` except you're marking a rectangular region.
|
| Command | Description |
|
||||||
- `mc/mark-sgml-tag-pair`: Mark the current opening and closing tag.
|
|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
- `mc/insert-numbers`: Insert increasing numbers for each cursor, top to bottom.
|
| `set-rectangular-region-anchor` | Think of this one as `set-mark` except you're marking a rectangular region. |
|
||||||
- `mc/insert-letters`: Insert increasing letters for each cursor, top to bottom.
|
| `mc/mark-sgml-tag-pair` | Mark the current opening and closing tag. |
|
||||||
- `mc/sort-regions`: Sort the marked regions alphabetically.
|
| `mc/insert-numbers` | Insert increasing numbers for each cursor, top to bottom. |
|
||||||
- `mc/reverse-regions`: Reverse the order of the marked regions.
|
| `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
|
## Tips and tricks
|
||||||
|
|
||||||
@@ -117,7 +147,7 @@ You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.co
|
|||||||
|
|
||||||
- Try pressing `mc/mark-next-like-this-word` or
|
- Try pressing `mc/mark-next-like-this-word` or
|
||||||
`mc/mark-next-like-this-symbol` with no region selected. It will
|
`mc/mark-next-like-this-symbol` with no region selected. It will
|
||||||
mark the word or symbol and add a cursor at the next occurance
|
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.
|
- Try pressing `mc/mark-all-like-this-dwim` on a tagname in html-mode.
|
||||||
|
|
||||||
@@ -136,6 +166,10 @@ You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.co
|
|||||||
- If you would like to keep the global bindings clean, and get custom keybindings
|
- If you would like to keep the global bindings clean, and get custom keybindings
|
||||||
when the region is active, you can try [region-bindings-mode](https://github.com/fgallina/region-bindings-mode).
|
when the region is active, you can try [region-bindings-mode](https://github.com/fgallina/region-bindings-mode).
|
||||||
|
|
||||||
|
- 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
|
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`.
|
||||||
|
|
||||||
@@ -174,7 +208,6 @@ run once to `mc/cmds-to-run-once` in ".mc-lists.el".
|
|||||||
|
|
||||||
* isearch-forward and isearch-backward aren't supported with multiple cursors.
|
* isearch-forward and isearch-backward aren't supported with multiple cursors.
|
||||||
If you want this functionality, you can use [phi-search](https://github.com/zk-phi/phi-search).
|
If you want this functionality, you can use [phi-search](https://github.com/zk-phi/phi-search).
|
||||||
* Commands run with `M-x` won't be repeated for all cursors.
|
|
||||||
* 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.
|
||||||
|
|||||||
@@ -50,6 +50,13 @@ Feature: Multiple cursors core
|
|||||||
And I press "C-!"
|
And I press "C-!"
|
||||||
Then I should see "This aatext contains the word aatext twice"
|
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
|
Scenario: Unknown command: no, don't do for all
|
||||||
Given I have bound C-! to another new command that inserts "a"
|
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"
|
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-!"
|
And I press "C-!"
|
||||||
Then I should see "This aatext contains the word text twice"
|
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
|
Scenario: Undo
|
||||||
Given I have cursors at "text" in "This text contains the word text twice"
|
Given I have cursors at "text" in "This text contains the word text twice"
|
||||||
When I press "M-f"
|
When I press "M-f"
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ Feature: Repeat last interactive command for fake cursors (mc/repeat-command)
|
|||||||
And I press "RET"
|
And I press "RET"
|
||||||
And I type "21"
|
And I type "21"
|
||||||
And I press "RET"
|
And I press "RET"
|
||||||
|
And I type "n"
|
||||||
And I press "C-:"
|
And I press "C-:"
|
||||||
And I press "y"
|
And I press "y"
|
||||||
And I execute the action chain
|
And I execute the action chain
|
||||||
@@ -27,6 +28,7 @@ Feature: Repeat last interactive command for fake cursors (mc/repeat-command)
|
|||||||
Scenario: Disable prompt
|
Scenario: Disable prompt
|
||||||
Given I have cursors at "text" in "This text/0000 contains the word text/1111 thrice (text/2222)"
|
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-repeat-command to t
|
||||||
|
When I set mc/always-run-for-all to t
|
||||||
When I start an action chain
|
When I start an action chain
|
||||||
And I press "M-x"
|
And I press "M-x"
|
||||||
And I type "zap-to-char"
|
And I type "zap-to-char"
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
(require 'cl) ;; For lexical-let
|
;; -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
|
(require 'multiple-cursors-core)
|
||||||
|
|
||||||
(When "^I mark next like this$"
|
(When "^I mark next like this$"
|
||||||
(lambda () (call-interactively 'mc/mark-next-like-this)))
|
(lambda () (call-interactively 'mc/mark-next-like-this)))
|
||||||
@@ -109,26 +111,27 @@
|
|||||||
|
|
||||||
(When "^I copy \"\\(.+\\)\" in another program$"
|
(When "^I copy \"\\(.+\\)\" in another program$"
|
||||||
(lambda (text)
|
(lambda (text)
|
||||||
(lexical-let ((text text))
|
|
||||||
(setq interprogram-paste-function
|
(setq interprogram-paste-function
|
||||||
#'(lambda () (let ((r text)) (setq text nil) r))))))
|
#'(lambda () (let ((r text)) (setq text nil) r)))))
|
||||||
|
|
||||||
(Given "^I have bound C-! to a lambda that inserts \"\\(.+\\)\"$"
|
(Given "^I have bound C-! to a lambda that inserts \"\\(.+\\)\"$"
|
||||||
(lambda (ins)
|
(lambda (ins)
|
||||||
(lexical-let ((ins ins))
|
(global-set-key (kbd "C-!") #'(lambda () (interactive) (insert ins)))))
|
||||||
(global-set-key (kbd "C-!") #'(lambda () (interactive) (insert ins))))))
|
|
||||||
|
|
||||||
(Given "^I have bound C-! to a new command that inserts \"\\(.+\\)\"$"
|
(Given "^I have bound C-! to a new command that inserts \"\\(.+\\)\"$"
|
||||||
(lambda (ins)
|
(lambda (ins)
|
||||||
(lexical-let ((ins ins))
|
|
||||||
(defun mc-test-temp-command () (interactive) (insert ins))
|
(defun mc-test-temp-command () (interactive) (insert ins))
|
||||||
(global-set-key (kbd "C-!") 'mc-test-temp-command))))
|
(global-set-key (kbd "C-!") 'mc-test-temp-command)))
|
||||||
|
|
||||||
(Given "^I have bound C-! to another new command that inserts \"\\(.+\\)\"$"
|
(Given "^I have bound C-! to another new command that inserts \"\\(.+\\)\"$"
|
||||||
(lambda (ins)
|
(lambda (ins)
|
||||||
(lexical-let ((ins ins))
|
|
||||||
(defun mc-test-temp-command-2 () (interactive) (insert ins))
|
(defun mc-test-temp-command-2 () (interactive) (insert ins))
|
||||||
(global-set-key (kbd "C-!") 'mc-test-temp-command-2))))
|
(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 \"_\"$"
|
(Given "^I have bound C-! to a keyboard macro that insert \"_\"$"
|
||||||
(lambda ()
|
(lambda ()
|
||||||
@@ -166,7 +169,7 @@
|
|||||||
|
|
||||||
(When "^I mark all \\(.+\\)$"
|
(When "^I mark all \\(.+\\)$"
|
||||||
(lambda (rest)
|
(lambda (rest)
|
||||||
(let ((func (intern (mapconcat 'identity
|
(let ((func (intern (mapconcat #'identity
|
||||||
(cons "mc/mark-all"
|
(cons "mc/mark-all"
|
||||||
(split-string rest))
|
(split-string rest))
|
||||||
"-"))))
|
"-"))))
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
|
;; -*- lexical-binding: t; -*-
|
||||||
|
(defvar multiple-cursors-root-path
|
||||||
(let* ((current-directory (file-name-directory load-file-name))
|
(let* ((current-directory (file-name-directory load-file-name))
|
||||||
(features-directory (expand-file-name ".." current-directory))
|
(features-directory (expand-file-name ".." current-directory)))
|
||||||
(project-directory (expand-file-name ".." features-directory)))
|
(expand-file-name ".." features-directory)))
|
||||||
(setq multiple-cursors-root-path project-directory)
|
(defvar multiple-cursors-util-path
|
||||||
(setq multiple-cursors-util-path (expand-file-name "util" project-directory)))
|
(expand-file-name "util" multiple-cursors-root-path))
|
||||||
|
|
||||||
(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)
|
||||||
@@ -45,6 +47,8 @@
|
|||||||
(subword-mode 0)
|
(subword-mode 0)
|
||||||
(wrap-region-mode 0)
|
(wrap-region-mode 0)
|
||||||
(setq set-mark-default-inactive nil)
|
(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)
|
(After)
|
||||||
|
|||||||
+10
-6
@@ -1,4 +1,4 @@
|
|||||||
;;; mc-cycle-cursors.el
|
;;; mc-cycle-cursors.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@
|
|||||||
(cursors-after-point (cl-remove-if (lambda (cursor)
|
(cursors-after-point (cl-remove-if (lambda (cursor)
|
||||||
(< (mc/cursor-beg cursor) point))
|
(< (mc/cursor-beg cursor) point))
|
||||||
cursors))
|
cursors))
|
||||||
(cursors-in-order (cl-sort cursors-after-point '< :key 'mc/cursor-beg)))
|
(cursors-in-order (cl-sort cursors-after-point #'< :key #'mc/cursor-beg)))
|
||||||
(car cursors-in-order)))
|
(car cursors-in-order)))
|
||||||
|
|
||||||
(defun mc/last-fake-cursor-before (point)
|
(defun mc/last-fake-cursor-before (point)
|
||||||
@@ -82,13 +82,17 @@
|
|||||||
(cursors-before-point (cl-remove-if (lambda (cursor)
|
(cursors-before-point (cl-remove-if (lambda (cursor)
|
||||||
(> (mc/cursor-end cursor) point))
|
(> (mc/cursor-end cursor) point))
|
||||||
cursors))
|
cursors))
|
||||||
(cursors-in-order (cl-sort cursors-before-point '> :key 'mc/cursor-end)))
|
(cursors-in-order (cl-sort cursors-before-point #'> :key #'mc/cursor-end)))
|
||||||
(car cursors-in-order)))
|
(car cursors-in-order)))
|
||||||
|
|
||||||
(cl-defun mc/cycle (next-cursor fallback-cursor loop-message)
|
(cl-defun mc/cycle (next-cursor fallback-cursor loop-message)
|
||||||
(when (null next-cursor)
|
(when (null next-cursor)
|
||||||
(when (eql 'stop (mc/handle-loop-condition loop-message))
|
(when (eql 'stop (mc/handle-loop-condition loop-message))
|
||||||
(return-from mc/cycle nil))
|
(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))
|
(setf next-cursor fallback-cursor))
|
||||||
(mc/create-fake-cursor-at-point)
|
(mc/create-fake-cursor-at-point)
|
||||||
(mc/pop-state-from-overlay next-cursor)
|
(mc/pop-state-from-overlay next-cursor)
|
||||||
@@ -106,8 +110,8 @@
|
|||||||
(mc/last-fake-cursor-before (point-max))
|
(mc/last-fake-cursor-before (point-max))
|
||||||
"We're already at the last cursor"))
|
"We're already at the last cursor"))
|
||||||
|
|
||||||
(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)
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -1,4 +1,4 @@
|
|||||||
;;; mc-edit-lines.el
|
;;; mc-edit-lines.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
@@ -50,12 +50,12 @@ that symbol is used instead of `mc/edit-lines-empty-lines'.
|
|||||||
Otherwise, if ARG negative, short lines will be ignored. Any
|
Otherwise, if ARG negative, short lines will be ignored. Any
|
||||||
other non-nil value will cause short lines to be padded."
|
other non-nil value will cause short lines to be padded."
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(when (not (and mark-active (/= (point) (mark))))
|
(unless mark-active
|
||||||
(error "Mark a set of lines first"))
|
(error "Mark a set of lines first"))
|
||||||
(mc/remove-fake-cursors)
|
(mc/remove-fake-cursors)
|
||||||
(let* ((col (current-column))
|
(let* ((col (current-column))
|
||||||
(point-line (line-number-at-pos))
|
(point-line (mc/line-number-at-pos))
|
||||||
(mark-line (progn (exchange-point-and-mark) (line-number-at-pos)))
|
(mark-line (progn (exchange-point-and-mark) (mc/line-number-at-pos)))
|
||||||
(direction (if (< point-line mark-line) :up :down))
|
(direction (if (< point-line mark-line) :up :down))
|
||||||
(style (cond
|
(style (cond
|
||||||
;; called from lisp
|
;; called from lisp
|
||||||
@@ -71,7 +71,7 @@ other non-nil value will cause short lines to be padded."
|
|||||||
(previous-logical-line 1 nil)
|
(previous-logical-line 1 nil)
|
||||||
(move-to-column col))
|
(move-to-column col))
|
||||||
;; Add the cursors
|
;; Add the cursors
|
||||||
(while (not (eq (line-number-at-pos) point-line))
|
(while (not (eq (mc/line-number-at-pos) point-line))
|
||||||
;; Pad the line
|
;; Pad the line
|
||||||
(when (eq style 'pad)
|
(when (eq style 'pad)
|
||||||
(while (< (current-column) col)
|
(while (< (current-column) col)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
;;; mc-hide-unmatched-lines.el
|
;;; mc-hide-unmatched-lines-mode.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright (C) 2014 Aleksey Fedotov
|
;; Copyright (C) 2014 Aleksey Fedotov
|
||||||
|
|
||||||
@@ -35,8 +35,8 @@
|
|||||||
(defvar hum/hide-unmatched-lines-mode-map (make-sparse-keymap)
|
(defvar hum/hide-unmatched-lines-mode-map (make-sparse-keymap)
|
||||||
"Keymap for hide unmatched lines is mainly for rebinding C-g")
|
"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 "C-g") #'hum/keyboard-quit)
|
||||||
(define-key hum/hide-unmatched-lines-mode-map (kbd "<return>") 'hum/keyboard-quit)
|
(define-key hum/hide-unmatched-lines-mode-map (kbd "<return>") #'hum/keyboard-quit)
|
||||||
|
|
||||||
(defun hum/keyboard-quit ()
|
(defun hum/keyboard-quit ()
|
||||||
"Leave hide-unmatched-lines mode"
|
"Leave hide-unmatched-lines mode"
|
||||||
@@ -54,16 +54,17 @@ also hum/lines-to-expand below and above) To make use of this
|
|||||||
mode press \"C-'\" while multiple-cursor-mode is active. You can
|
mode press \"C-'\" while multiple-cursor-mode is active. You can
|
||||||
still edit lines while you are in mc-hide-unmatched-lines
|
still edit lines while you are in mc-hide-unmatched-lines
|
||||||
mode. To leave this mode press <return> or \"C-g\""
|
mode. To leave this mode press <return> or \"C-g\""
|
||||||
nil " hu"
|
:init-value nil
|
||||||
hum/hide-unmatched-lines-mode-map
|
:lighter " hu"
|
||||||
|
:keymap hum/hide-unmatched-lines-mode-map
|
||||||
(if mc-hide-unmatched-lines-mode
|
(if mc-hide-unmatched-lines-mode
|
||||||
;;just in case if mc mode will be disabled while hide-unmatched-lines is active
|
;;just in case if mc mode will be disabled while hide-unmatched-lines is active
|
||||||
(progn
|
(progn
|
||||||
(hum/hide-unmatched-lines)
|
(hum/hide-unmatched-lines)
|
||||||
(add-hook 'multiple-cursors-mode-disabled-hook 'hum/disable-hum-mode t t))
|
(add-hook 'multiple-cursors-mode-disabled-hook #'hum/disable-hum-mode t t))
|
||||||
(progn
|
(progn
|
||||||
(hum/unhide-unmatched-lines)
|
(hum/unhide-unmatched-lines)
|
||||||
(remove-hook 'multiple-cursors-mode-disabled-hook 'hum/disable-hum-mode))))
|
(remove-hook 'multiple-cursors-mode-disabled-hook #'hum/disable-hum-mode))))
|
||||||
|
|
||||||
(defconst hum/invisible-overlay-name 'hum/invisible-overlay-name)
|
(defconst hum/invisible-overlay-name 'hum/invisible-overlay-name)
|
||||||
|
|
||||||
@@ -73,7 +74,7 @@ mode. To leave this mode press <return> or \"C-g\""
|
|||||||
:group 'multiple-cursors)
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
(defcustom hum/placeholder "..."
|
(defcustom hum/placeholder "..."
|
||||||
"Placeholder which will be placed insted of hiden text"
|
"Placeholder which will be placed instead of hidden text"
|
||||||
:type '(string)
|
:type '(string)
|
||||||
:group 'multiple-cursors)
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
@@ -103,5 +104,6 @@ mode. To leave this mode press <return> or \"C-g\""
|
|||||||
(defun hum/unhide-unmatched-lines ()
|
(defun hum/unhide-unmatched-lines ()
|
||||||
(remove-overlays nil nil hum/invisible-overlay-name t))
|
(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)
|
(provide 'mc-hide-unmatched-lines-mode)
|
||||||
(define-key mc/keymap (kbd "C-'") 'mc-hide-unmatched-lines-mode)
|
|
||||||
|
|||||||
+80
-49
@@ -1,4 +1,4 @@
|
|||||||
;;; mc-mark-more.el
|
;;; mc-mark-more.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
@@ -29,6 +29,7 @@
|
|||||||
|
|
||||||
(require 'multiple-cursors-core)
|
(require 'multiple-cursors-core)
|
||||||
(require 'thingatpt)
|
(require 'thingatpt)
|
||||||
|
(require 'sgml-mode)
|
||||||
|
|
||||||
(defun mc/cursor-end (cursor)
|
(defun mc/cursor-end (cursor)
|
||||||
(if (overlay-get cursor 'mark-active)
|
(if (overlay-get cursor 'mark-active)
|
||||||
@@ -96,8 +97,8 @@ to (point)), or nil."
|
|||||||
"How should mc/mark-more-* search for more matches?
|
"How should mc/mark-more-* search for more matches?
|
||||||
|
|
||||||
Match everything: nil
|
Match everything: nil
|
||||||
Match only whole words: 'words
|
Match only whole words: \\='words
|
||||||
Match only whole symbols: 'symbols
|
Match only whole symbols: \\='symbols
|
||||||
|
|
||||||
Use like case-fold-search, don't recommend setting it globally.")
|
Use like case-fold-search, don't recommend setting it globally.")
|
||||||
|
|
||||||
@@ -190,7 +191,7 @@ With zero ARG, skip the last one and mark next."
|
|||||||
(defun mc/mark-next-word-like-this (arg)
|
(defun mc/mark-next-word-like-this (arg)
|
||||||
"Find and mark the next word of the buffer matching the currently active region
|
"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
|
The matching region must be a whole word to be a match
|
||||||
If no region is active, mark the symbol at the point and find the next match
|
If no region is active add a cursor on the next line
|
||||||
With negative ARG, delete the last one instead.
|
With negative ARG, delete the last one instead.
|
||||||
With zero ARG, skip the last one and mark next."
|
With zero ARG, skip the last one and mark next."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
@@ -201,7 +202,7 @@ With zero ARG, skip the last one and mark next."
|
|||||||
(defun mc/mark-next-symbol-like-this (arg)
|
(defun mc/mark-next-symbol-like-this (arg)
|
||||||
"Find and mark the next symbol of the buffer matching the currently active region
|
"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
|
The matching region must be a whole symbol to be a match
|
||||||
If no region is active, mark the symbol at the point and find the next match
|
If no region is active add a cursor on the next line
|
||||||
With negative ARG, delete the last one instead.
|
With negative ARG, delete the last one instead.
|
||||||
With zero ARG, skip the last one and mark next."
|
With zero ARG, skip the last one and mark next."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
@@ -210,9 +211,13 @@ With zero ARG, skip the last one and mark next."
|
|||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-previous-like-this (arg)
|
(defun mc/mark-previous-like-this (arg)
|
||||||
"Find and mark the previous part of the buffer matching the currently active region
|
"Find and mark the previous part of the buffer matching the
|
||||||
If no region is active add a cursor on the previous line
|
currently active region.
|
||||||
|
|
||||||
|
If no region is active ,add a cursor on the previous line.
|
||||||
|
|
||||||
With negative ARG, delete the last one instead.
|
With negative ARG, delete the last one instead.
|
||||||
|
|
||||||
With zero ARG, skip the last one and mark next."
|
With zero ARG, skip the last one and mark next."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(if (< arg 0)
|
(if (< arg 0)
|
||||||
@@ -227,9 +232,14 @@ With zero ARG, skip the last one and mark next."
|
|||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-previous-like-this-word (arg)
|
(defun mc/mark-previous-like-this-word (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
|
||||||
If no region is active, mark the word at the point and find the previous match
|
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 negative ARG, delete the last one instead.
|
||||||
|
|
||||||
With zero ARG, skip the last one and mark previous."
|
With zero ARG, skip the last one and mark previous."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(if (< arg 0)
|
(if (< arg 0)
|
||||||
@@ -244,9 +254,14 @@ With zero ARG, skip the last one and mark previous."
|
|||||||
(mc/maybe-multiple-cursors-mode))
|
(mc/maybe-multiple-cursors-mode))
|
||||||
|
|
||||||
(defun mc/mark-previous-like-this-symbol (arg)
|
(defun mc/mark-previous-like-this-symbol (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
|
||||||
If no region is active, mark the symbol at the point and find the previous match
|
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 negative ARG, delete the last one instead.
|
||||||
|
|
||||||
With zero ARG, skip the last one and mark previous."
|
With zero ARG, skip the last one and mark previous."
|
||||||
(interactive "p")
|
(interactive "p")
|
||||||
(if (< arg 0)
|
(if (< arg 0)
|
||||||
@@ -263,10 +278,15 @@ With zero ARG, skip the last one and mark previous."
|
|||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-previous-word-like-this (arg)
|
(defun mc/mark-previous-word-like-this (arg)
|
||||||
"Find and mark the previous part of the buffer matching the currently active region
|
"Find and mark the previous part of the buffer matching the
|
||||||
The matching region must be a whole word to be a match
|
currently active region.
|
||||||
If no region is active add a cursor on the previous line
|
|
||||||
|
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 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")
|
||||||
(let ((mc/enclose-search-term 'words))
|
(let ((mc/enclose-search-term 'words))
|
||||||
@@ -274,17 +294,22 @@ With zero ARG, skip the last one and mark next."
|
|||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-previous-symbol-like-this (arg)
|
(defun mc/mark-previous-symbol-like-this (arg)
|
||||||
"Find and mark the previous part of the buffer matching the currently active region
|
"Find and mark the previous part of the buffer matching
|
||||||
The matching region must be a whole symbol to be a match
|
the currently active region.
|
||||||
If no region is active add a cursor on the previous line
|
|
||||||
|
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 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")
|
||||||
(let ((mc/enclose-search-term 'symbols))
|
(let ((mc/enclose-search-term 'symbols))
|
||||||
(mc/mark-previous-like-this arg)))
|
(mc/mark-previous-like-this arg)))
|
||||||
|
|
||||||
(defun mc/mark-lines (num-lines direction)
|
(defun mc/mark-lines (num-lines direction)
|
||||||
(dotimes (i (if (= num-lines 0) 1 num-lines))
|
(dotimes (_ (if (= num-lines 0) 1 num-lines))
|
||||||
(mc/save-excursion
|
(mc/save-excursion
|
||||||
(let ((furthest-cursor (cl-ecase direction
|
(let ((furthest-cursor (cl-ecase direction
|
||||||
(forwards (mc/furthest-cursor-after-point))
|
(forwards (mc/furthest-cursor-after-point))
|
||||||
@@ -324,13 +349,15 @@ With zero ARG, skip the last one and mark next."
|
|||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/skip-to-next-like-this ()
|
(defun mc/skip-to-next-like-this ()
|
||||||
"Skip the current one and select the next part of the buffer matching the currently active region."
|
"Skip the current one and select the next part of the buffer
|
||||||
|
matching the currently active region."
|
||||||
(interactive)
|
(interactive)
|
||||||
(mc/mark-next-like-this 0))
|
(mc/mark-next-like-this 0))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/skip-to-previous-like-this ()
|
(defun mc/skip-to-previous-like-this ()
|
||||||
"Skip the current one and select the prev part of the buffer matching the currently active region."
|
"Skip the current one and select the prev part of the buffer
|
||||||
|
matching the currently active region."
|
||||||
(interactive)
|
(interactive)
|
||||||
(mc/mark-previous-like-this 0))
|
(mc/mark-previous-like-this 0))
|
||||||
|
|
||||||
@@ -355,7 +382,7 @@ With zero ARG, skip the last one and mark next."
|
|||||||
(when point-first (exchange-point-and-mark)))))
|
(when point-first (exchange-point-and-mark)))))
|
||||||
(if (> (mc/num-cursors) 1)
|
(if (> (mc/num-cursors) 1)
|
||||||
(multiple-cursors-mode 1)
|
(multiple-cursors-mode 1)
|
||||||
(multiple-cursors-mode 0)))
|
(mc/disable-multiple-cursors-mode)))
|
||||||
|
|
||||||
(defun mc--select-thing-at-point (thing)
|
(defun mc--select-thing-at-point (thing)
|
||||||
(let ((bound (bounds-of-thing-at-point thing)))
|
(let ((bound (bounds-of-thing-at-point thing)))
|
||||||
@@ -393,16 +420,18 @@ With zero ARG, skip the last one and mark next."
|
|||||||
(progn
|
(progn
|
||||||
(mc/remove-fake-cursors)
|
(mc/remove-fake-cursors)
|
||||||
(goto-char beg)
|
(goto-char beg)
|
||||||
|
(let ((lastmatch))
|
||||||
(while (search-forward search end t)
|
(while (search-forward search end t)
|
||||||
(push-mark (match-beginning 0))
|
(push-mark (match-beginning 0))
|
||||||
(mc/create-fake-cursor-at-point))
|
(mc/create-fake-cursor-at-point)
|
||||||
(let ((first (mc/furthest-cursor-before-point)))
|
(setq lastmatch t))
|
||||||
(if (not first)
|
(unless lastmatch
|
||||||
(error "Search failed for %S" search)
|
(error "Search failed for %S" search)))
|
||||||
(mc/pop-state-from-overlay first)))
|
(goto-char (match-end 0))
|
||||||
(if (> (mc/num-cursors) 1)
|
(if (< (mc/num-cursors) 3)
|
||||||
(multiple-cursors-mode 1)
|
(mc/disable-multiple-cursors-mode)
|
||||||
(multiple-cursors-mode 0))))))
|
(mc/pop-state-from-overlay (mc/furthest-cursor-before-point))
|
||||||
|
(multiple-cursors-mode 1))))))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-all-in-region-regexp (beg end)
|
(defun mc/mark-all-in-region-regexp (beg end)
|
||||||
@@ -427,7 +456,7 @@ With zero ARG, skip the last one and mark next."
|
|||||||
(error "Search failed for %S" search)))
|
(error "Search failed for %S" search)))
|
||||||
(goto-char (match-end 0))
|
(goto-char (match-end 0))
|
||||||
(if (< (mc/num-cursors) 3)
|
(if (< (mc/num-cursors) 3)
|
||||||
(multiple-cursors-mode 0)
|
(mc/disable-multiple-cursors-mode)
|
||||||
(mc/pop-state-from-overlay (mc/furthest-cursor-before-point))
|
(mc/pop-state-from-overlay (mc/furthest-cursor-before-point))
|
||||||
(multiple-cursors-mode 1))))))
|
(multiple-cursors-mode 1))))))
|
||||||
|
|
||||||
@@ -469,31 +498,40 @@ remove the keymap depends on user input and KEEP-PRED:
|
|||||||
|
|
||||||
(push alist emulation-mode-map-alists))))
|
(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
|
;;;###autoload
|
||||||
(defun mc/mark-more-like-this-extended ()
|
(defun mc/mark-more-like-this-extended ()
|
||||||
"Like mark-more-like-this, but then lets you adjust with arrows key.
|
"Like mark-more-like-this, but then lets you adjust with arrow keys.
|
||||||
The adjustments work like this:
|
The adjustments work like this:
|
||||||
|
|
||||||
<up> Mark previous like this and set direction to 'up
|
<up> Mark previous like this and set direction to \\='up
|
||||||
<down> Mark next like this and set direction to 'down
|
<down> Mark next like this and set direction to \\='down
|
||||||
|
|
||||||
If direction is 'up:
|
If direction is \\='up:
|
||||||
|
|
||||||
<left> Skip past the cursor furthest up
|
<left> Skip past the cursor furthest up
|
||||||
<right> Remove the cursor furthest up
|
<right> Remove the cursor furthest up
|
||||||
|
|
||||||
If direction is 'down:
|
If direction is \\='down:
|
||||||
|
|
||||||
<left> Remove the cursor furthest down
|
<left> Remove the cursor furthest down
|
||||||
<right> Skip past 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'."
|
The bindings for these commands can be changed.
|
||||||
|
See `mc/mark-more-like-this-extended-keymap'."
|
||||||
(interactive)
|
(interactive)
|
||||||
(mc/mmlte--down)
|
(mc/mmlte--down)
|
||||||
(set-temporary-overlay-map mc/mark-more-like-this-extended-keymap t))
|
(set-transient-map mc/mark-more-like-this-extended-keymap t))
|
||||||
|
|
||||||
(defvar mc/mark-more-like-this-extended-direction nil
|
(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?")
|
"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)
|
(make-variable-buffer-local 'mc/mark-more-like-this-extended)
|
||||||
|
|
||||||
@@ -528,13 +566,6 @@ The bindings for these commands can be changed. See `mc/mark-more-like-this-exte
|
|||||||
(mc/skip-to-next-like-this))
|
(mc/skip-to-next-like-this))
|
||||||
(mc/mmlte--message))
|
(mc/mmlte--message))
|
||||||
|
|
||||||
(defvar mc/mark-more-like-this-extended-keymap (make-sparse-keymap))
|
|
||||||
|
|
||||||
(define-key mc/mark-more-like-this-extended-keymap (kbd "<up>") 'mc/mmlte--up)
|
|
||||||
(define-key mc/mark-more-like-this-extended-keymap (kbd "<down>") 'mc/mmlte--down)
|
|
||||||
(define-key mc/mark-more-like-this-extended-keymap (kbd "<left>") 'mc/mmlte--left)
|
|
||||||
(define-key mc/mark-more-like-this-extended-keymap (kbd "<right>") 'mc/mmlte--right)
|
|
||||||
|
|
||||||
(defvar mc--restrict-mark-all-to-symbols nil)
|
(defvar mc--restrict-mark-all-to-symbols nil)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
@@ -579,8 +610,8 @@ If the region is inactive or on a single line, it will behave like
|
|||||||
(interactive "P")
|
(interactive "P")
|
||||||
(if (and (use-region-p)
|
(if (and (use-region-p)
|
||||||
(not (> (mc/num-cursors) 1))
|
(not (> (mc/num-cursors) 1))
|
||||||
(not (= (line-number-at-pos (region-beginning))
|
(not (= (mc/line-number-at-pos (region-beginning))
|
||||||
(line-number-at-pos (region-end)))))
|
(mc/line-number-at-pos (region-end)))))
|
||||||
(if arg
|
(if arg
|
||||||
(call-interactively 'mc/edit-lines)
|
(call-interactively 'mc/edit-lines)
|
||||||
(call-interactively 'mc/mark-all-in-region))
|
(call-interactively 'mc/mark-all-in-region))
|
||||||
@@ -639,7 +670,7 @@ If the region is inactive or on a single line, it will behave like
|
|||||||
(last
|
(last
|
||||||
(progn
|
(progn
|
||||||
(when (looking-at "<") (forward-char 1))
|
(when (looking-at "<") (forward-char 1))
|
||||||
(when (looking-back ">") (forward-char -1))
|
(when (looking-back ">" 1) (forward-char -1))
|
||||||
(sgml-get-context)))))
|
(sgml-get-context)))))
|
||||||
|
|
||||||
(defun mc--on-tag-name-p ()
|
(defun mc--on-tag-name-p ()
|
||||||
@@ -675,7 +706,7 @@ already there."
|
|||||||
(mc/maybe-multiple-cursors-mode)))
|
(mc/maybe-multiple-cursors-mode)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defalias 'mc/add-cursor-on-click 'mc/toggle-cursor-on-click)
|
(defalias 'mc/add-cursor-on-click #'mc/toggle-cursor-on-click)
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/mark-sgml-tag-pair ()
|
(defun mc/mark-sgml-tag-pair ()
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
;;; mc-mark-pop.el --- Pop cursors off of the mark stack
|
;;; mc-mark-pop.el --- Pop cursors off of the mark stack -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
(require 'multiple-cursors-core)
|
(require 'multiple-cursors-core)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
;;; mc-separate-operations.el - functions that work differently on each cursor
|
;;; mc-separate-operations.el --- Functions that work differently on each cursor -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
@@ -106,7 +106,8 @@
|
|||||||
(progn
|
(progn
|
||||||
(mc/mark-next-lines 1)
|
(mc/mark-next-lines 1)
|
||||||
(mc/reverse-regions)
|
(mc/reverse-regions)
|
||||||
(multiple-cursors-mode 0))
|
(mc/disable-multiple-cursors-mode)
|
||||||
|
)
|
||||||
(unless (use-region-p)
|
(unless (use-region-p)
|
||||||
(mc/execute-command-for-all-cursors 'mark-sexp))
|
(mc/execute-command-for-all-cursors 'mark-sexp))
|
||||||
(setq mc--strings-to-replace (nreverse (mc--ordered-region-strings)))
|
(setq mc--strings-to-replace (nreverse (mc--ordered-region-strings)))
|
||||||
@@ -117,14 +118,14 @@
|
|||||||
(interactive)
|
(interactive)
|
||||||
(unless (use-region-p)
|
(unless (use-region-p)
|
||||||
(mc/execute-command-for-all-cursors 'mark-sexp))
|
(mc/execute-command-for-all-cursors 'mark-sexp))
|
||||||
(setq mc--strings-to-replace (sort (mc--ordered-region-strings) 'string<))
|
(setq mc--strings-to-replace (sort (mc--ordered-region-strings) #'string<))
|
||||||
(mc--replace-region-strings))
|
(mc--replace-region-strings))
|
||||||
|
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(defun mc/vertical-align (character)
|
(defun mc/vertical-align (character)
|
||||||
"Aligns all cursors vertically with a given CHARACTER to the one with the
|
"Aligns all cursors vertically with a given CHARACTER to the one with the
|
||||||
highest colum number (the rightest).
|
highest column number (the rightest).
|
||||||
Might not behave as intended if more than one cursors are on the same line."
|
Might not behave as intended if more than one cursors are on the same line."
|
||||||
(interactive "c")
|
(interactive "c")
|
||||||
(let ((rightest-column (current-column)))
|
(let ((rightest-column (current-column)))
|
||||||
|
|||||||
+421
-327
@@ -1,4 +1,4 @@
|
|||||||
;;; multiple-cursors-core.el --- An experiment in multiple cursors for emacs.
|
;;; multiple-cursors-core.el --- An experiment in multiple cursors for Emacs -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
@@ -28,8 +28,6 @@
|
|||||||
(require 'cl-lib)
|
(require 'cl-lib)
|
||||||
(require 'rect)
|
(require 'rect)
|
||||||
|
|
||||||
(defvar mc--read-char)
|
|
||||||
|
|
||||||
(defface mc/cursor-face
|
(defface mc/cursor-face
|
||||||
'((t (:inverse-video t)))
|
'((t (:inverse-video t)))
|
||||||
"The face used for fake cursors"
|
"The face used for fake cursors"
|
||||||
@@ -40,6 +38,18 @@
|
|||||||
"The face used for fake cursors if the cursor-type is bar"
|
"The face used for fake cursors if the cursor-type is bar"
|
||||||
:group 'multiple-cursors)
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
|
(defcustom mc/match-cursor-style t
|
||||||
|
"If non-nil, attempt to match the cursor style that the user
|
||||||
|
has selected. Namely, use vertical bars the user has configured
|
||||||
|
Emacs to use that cursor.
|
||||||
|
|
||||||
|
If nil, just use standard rectangle cursors for all fake cursors.
|
||||||
|
|
||||||
|
In some modes/themes, the bar fake cursors are either not
|
||||||
|
rendered or shift text."
|
||||||
|
:type '(boolean)
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
(defface mc/region-face
|
(defface mc/region-face
|
||||||
'((t :inherit region))
|
'((t :inherit region))
|
||||||
"The face used for fake regions"
|
"The face used for fake regions"
|
||||||
@@ -57,7 +67,7 @@
|
|||||||
(cons (cons 'apply (cons 'activate-cursor-for-undo (list id))) buffer-undo-list))))))
|
(cons (cons 'apply (cons 'activate-cursor-for-undo (list id))) buffer-undo-list))))))
|
||||||
|
|
||||||
(defun mc/all-fake-cursors (&optional start end)
|
(defun mc/all-fake-cursors (&optional start end)
|
||||||
(cl-remove-if-not 'mc/fake-cursor-p
|
(cl-remove-if-not #'mc/fake-cursor-p
|
||||||
(overlays-in (or start (point-min))
|
(overlays-in (or start (point-min))
|
||||||
(or end (point-max)))))
|
(or end (point-max)))))
|
||||||
|
|
||||||
@@ -85,7 +95,7 @@
|
|||||||
(mapc #'(lambda (cursor)
|
(mapc #'(lambda (cursor)
|
||||||
(when (mc/fake-cursor-p cursor)
|
(when (mc/fake-cursor-p cursor)
|
||||||
,@forms))
|
,@forms))
|
||||||
(sort (overlays-in (point-min) (point-max)) 'mc--compare-by-overlay-start))
|
(sort (overlays-in (point-min) (point-max)) #'mc--compare-by-overlay-start))
|
||||||
(mc/pop-state-from-overlay (mc/cursor-with-id ,rci)))))
|
(mc/pop-state-from-overlay (mc/cursor-with-id ,rci)))))
|
||||||
|
|
||||||
(defmacro mc/save-window-scroll (&rest forms)
|
(defmacro mc/save-window-scroll (&rest forms)
|
||||||
@@ -105,14 +115,33 @@
|
|||||||
|
|
||||||
(defun mc/cursor-is-bar ()
|
(defun mc/cursor-is-bar ()
|
||||||
"Return non-nil if the cursor is a bar."
|
"Return non-nil if the cursor is a bar."
|
||||||
|
(let ((cursor-type
|
||||||
|
(if (eq cursor-type t)
|
||||||
|
(frame-parameter nil 'cursor-type)
|
||||||
|
cursor-type)))
|
||||||
(or (eq cursor-type 'bar)
|
(or (eq cursor-type 'bar)
|
||||||
(and (listp cursor-type)
|
(and (listp cursor-type)
|
||||||
(eq (car cursor-type) 'bar))))
|
(eq (car cursor-type) 'bar)))))
|
||||||
|
|
||||||
|
(if (>= emacs-major-version 28)
|
||||||
|
(defalias 'mc/line-number-at-pos #'line-number-at-pos)
|
||||||
|
(defun mc/line-number-at-pos (&optional pos absolute)
|
||||||
|
"Faster implementation of `line-number-at-pos'."
|
||||||
|
(if pos
|
||||||
|
(save-excursion
|
||||||
|
(if absolute
|
||||||
|
(save-restriction
|
||||||
|
(widen)
|
||||||
|
(goto-char pos)
|
||||||
|
(string-to-number (format-mode-line "%l")))
|
||||||
|
(goto-char pos)
|
||||||
|
(string-to-number (format-mode-line "%l"))))
|
||||||
|
(string-to-number (format-mode-line "%l")))))
|
||||||
|
|
||||||
(defun mc/make-cursor-overlay-at-eol (pos)
|
(defun mc/make-cursor-overlay-at-eol (pos)
|
||||||
"Create overlay to look like cursor at end of line."
|
"Create overlay to look like cursor at end of line."
|
||||||
(let ((overlay (make-overlay pos pos nil nil nil)))
|
(let ((overlay (make-overlay pos pos nil nil nil)))
|
||||||
(if (mc/cursor-is-bar)
|
(if (and mc/match-cursor-style (mc/cursor-is-bar))
|
||||||
(overlay-put overlay 'before-string (propertize "|" 'face 'mc/cursor-bar-face))
|
(overlay-put overlay 'before-string (propertize "|" 'face 'mc/cursor-bar-face))
|
||||||
(overlay-put overlay 'after-string (propertize " " 'face 'mc/cursor-face)))
|
(overlay-put overlay 'after-string (propertize " " 'face 'mc/cursor-face)))
|
||||||
overlay))
|
overlay))
|
||||||
@@ -120,7 +149,7 @@
|
|||||||
(defun mc/make-cursor-overlay-inline (pos)
|
(defun mc/make-cursor-overlay-inline (pos)
|
||||||
"Create overlay to look like cursor inside text."
|
"Create overlay to look like cursor inside text."
|
||||||
(let ((overlay (make-overlay pos (1+ pos) nil nil nil)))
|
(let ((overlay (make-overlay pos (1+ pos) nil nil nil)))
|
||||||
(if (mc/cursor-is-bar)
|
(if (and mc/match-cursor-style (mc/cursor-is-bar))
|
||||||
(overlay-put overlay 'before-string (propertize "|" 'face 'mc/cursor-bar-face))
|
(overlay-put overlay 'before-string (propertize "|" 'face 'mc/cursor-bar-face))
|
||||||
(overlay-put overlay 'face 'mc/cursor-face))
|
(overlay-put overlay 'face 'mc/cursor-face))
|
||||||
overlay))
|
overlay))
|
||||||
@@ -149,7 +178,18 @@ highlights the entire width of the window."
|
|||||||
autopair-action
|
autopair-action
|
||||||
autopair-wrap-action
|
autopair-wrap-action
|
||||||
temporary-goal-column
|
temporary-goal-column
|
||||||
er/history)
|
er/history
|
||||||
|
dabbrev--abbrev-char-regexp
|
||||||
|
dabbrev--check-other-buffers
|
||||||
|
dabbrev--friend-buffer-list
|
||||||
|
dabbrev--last-abbrev-location
|
||||||
|
dabbrev--last-abbreviation
|
||||||
|
dabbrev--last-buffer
|
||||||
|
dabbrev--last-buffer-found
|
||||||
|
dabbrev--last-direction
|
||||||
|
dabbrev--last-expansion
|
||||||
|
dabbrev--last-expansion-location
|
||||||
|
dabbrev--last-table)
|
||||||
"A list of vars that need to be tracked on a per-cursor basis.")
|
"A list of vars that need to be tracked on a per-cursor basis.")
|
||||||
|
|
||||||
(defun mc/store-current-state-in-overlay (o)
|
(defun mc/store-current-state-in-overlay (o)
|
||||||
@@ -214,8 +254,11 @@ If this value is nil, there is no ceiling."
|
|||||||
:group 'multiple-cursors)
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
(defun mc/create-fake-cursor-at-point (&optional id)
|
(defun mc/create-fake-cursor-at-point (&optional id)
|
||||||
"Add a fake cursor and possibly a fake active region overlay based on point and mark.
|
"Add a fake cursor and possibly a fake active region overlay
|
||||||
Saves the current state in the overlay to be restored later."
|
based on point and mark.
|
||||||
|
|
||||||
|
Saves the current state in the overlay
|
||||||
|
to be restored later."
|
||||||
(unless mc--max-cursors-original
|
(unless mc--max-cursors-original
|
||||||
(setq mc--max-cursors-original mc/max-cursors))
|
(setq mc--max-cursors-original mc/max-cursors))
|
||||||
(when mc/max-cursors
|
(when mc/max-cursors
|
||||||
@@ -235,7 +278,8 @@ Saves the current state in the overlay to be restored later."
|
|||||||
overlay))
|
overlay))
|
||||||
|
|
||||||
(defun mc/execute-command (cmd)
|
(defun mc/execute-command (cmd)
|
||||||
"Run command, simulating the parts of the command loop that makes sense for fake cursors."
|
"Run command, simulating the parts of the command loop that
|
||||||
|
makes sense for fake cursors."
|
||||||
(setq this-command cmd)
|
(setq this-command cmd)
|
||||||
(run-hooks 'pre-command-hook)
|
(run-hooks 'pre-command-hook)
|
||||||
(unless (eq this-command 'ignore)
|
(unless (eq this-command 'ignore)
|
||||||
@@ -246,6 +290,8 @@ Saves the current state in the overlay to be restored later."
|
|||||||
(defvar mc--executing-command-for-fake-cursor nil)
|
(defvar mc--executing-command-for-fake-cursor nil)
|
||||||
|
|
||||||
(defun mc/execute-command-for-fake-cursor (cmd cursor)
|
(defun mc/execute-command-for-fake-cursor (cmd cursor)
|
||||||
|
(defvar annoying-arrows-mode)
|
||||||
|
(defvar smooth-scroll-margin)
|
||||||
(let ((mc--executing-command-for-fake-cursor t)
|
(let ((mc--executing-command-for-fake-cursor t)
|
||||||
(id (overlay-get cursor 'mc-id))
|
(id (overlay-get cursor 'mc-id))
|
||||||
(annoying-arrows-mode nil)
|
(annoying-arrows-mode nil)
|
||||||
@@ -277,28 +323,35 @@ cursor with updated info."
|
|||||||
;; Intercept some reading commands so you won't have to
|
;; Intercept some reading commands so you won't have to
|
||||||
;; answer them for every single cursor
|
;; answer them for every single cursor
|
||||||
|
|
||||||
(defvar mc--read-char nil)
|
(defvar mc--input-function-cache nil)
|
||||||
(defvar multiple-cursors-mode nil)
|
|
||||||
(defadvice read-char (around mc-support activate)
|
|
||||||
(if (not multiple-cursors-mode)
|
|
||||||
ad-do-it
|
|
||||||
(unless mc--read-char
|
|
||||||
(setq mc--read-char ad-do-it))
|
|
||||||
(setq ad-return-value mc--read-char)))
|
|
||||||
|
|
||||||
(defvar mc--read-quoted-char nil)
|
|
||||||
(defadvice read-quoted-char (around mc-support activate)
|
|
||||||
(if (not multiple-cursors-mode)
|
|
||||||
ad-do-it
|
|
||||||
(unless mc--read-quoted-char
|
|
||||||
(setq mc--read-quoted-char ad-do-it))
|
|
||||||
(setq ad-return-value mc--read-quoted-char)))
|
|
||||||
|
|
||||||
(defun mc--reset-read-prompts ()
|
(defun mc--reset-read-prompts ()
|
||||||
(setq mc--read-char nil)
|
(setq mc--input-function-cache nil))
|
||||||
(setq mc--read-quoted-char nil))
|
|
||||||
|
|
||||||
(mc--reset-read-prompts)
|
(defmacro mc--cache-input-function (fn-name args-cache-key-fn)
|
||||||
|
"Advise FN-NAME to cache its value in a private variable. Cache
|
||||||
|
is to be used by mc/execute-command-for-all-fake-cursors and
|
||||||
|
caches will be reset by mc--reset-read-prompts. ARGS-CACHE-KEY-FN
|
||||||
|
should transform FN-NAME's args to a unique cache-key so that
|
||||||
|
different calls to FN-NAME during a command can return multiple
|
||||||
|
values."
|
||||||
|
(let ((mc-name (intern (concat "mc--" (symbol-name fn-name)))))
|
||||||
|
`(progn
|
||||||
|
(defun ,mc-name (orig-fun &rest args)
|
||||||
|
(if (not (bound-and-true-p multiple-cursors-mode))
|
||||||
|
(apply orig-fun args)
|
||||||
|
(let* ((cache-key (cons ,(symbol-name fn-name) (,args-cache-key-fn args)))
|
||||||
|
(cached-value (assoc cache-key mc--input-function-cache))
|
||||||
|
(return-value (if cached-value (cdr cached-value) (apply orig-fun args))))
|
||||||
|
(unless cached-value
|
||||||
|
(push (cons cache-key return-value) mc--input-function-cache))
|
||||||
|
return-value)))
|
||||||
|
(advice-add ',fn-name :around #',mc-name))))
|
||||||
|
|
||||||
|
(mc--cache-input-function read-char car)
|
||||||
|
(mc--cache-input-function read-quoted-char car)
|
||||||
|
(mc--cache-input-function register-read-with-preview car) ; used by insert-register
|
||||||
|
(mc--cache-input-function read-char-from-minibuffer car) ; used by zap-to-char
|
||||||
|
|
||||||
(defun mc/fake-cursor-p (o)
|
(defun mc/fake-cursor-p (o)
|
||||||
"Predicate to check if an overlay is a fake cursor"
|
"Predicate to check if an overlay is a fake cursor"
|
||||||
@@ -313,8 +366,10 @@ cursor with updated info."
|
|||||||
(defvar mc--stored-state-for-undo nil
|
(defvar mc--stored-state-for-undo nil
|
||||||
"Variable to keep the state of the real cursor while undoing a fake one")
|
"Variable to keep the state of the real cursor while undoing a fake one")
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
(defun activate-cursor-for-undo (id)
|
(defun activate-cursor-for-undo (id)
|
||||||
"Called when undoing to temporarily activate the fake cursor which action is being undone."
|
"Called when undoing to temporarily activate the fake cursor
|
||||||
|
which action is being undone."
|
||||||
(let ((cursor (mc/cursor-with-id id)))
|
(let ((cursor (mc/cursor-with-id id)))
|
||||||
(when cursor
|
(when cursor
|
||||||
(setq mc--stored-state-for-undo (mc/store-current-state-in-overlay
|
(setq mc--stored-state-for-undo (mc/store-current-state-in-overlay
|
||||||
@@ -338,297 +393,6 @@ cursor with updated info."
|
|||||||
:type '(boolean)
|
:type '(boolean)
|
||||||
:group 'multiple-cursors)
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
(defun mc/prompt-for-inclusion-in-whitelist (original-command)
|
|
||||||
"Asks the user, then adds the command either to the once-list or the all-list."
|
|
||||||
(let ((all-p (y-or-n-p (format "Do %S for all cursors?" original-command))))
|
|
||||||
(if all-p
|
|
||||||
(add-to-list 'mc/cmds-to-run-for-all original-command)
|
|
||||||
(add-to-list 'mc/cmds-to-run-once original-command))
|
|
||||||
(mc/save-lists)
|
|
||||||
all-p))
|
|
||||||
|
|
||||||
(defun mc/num-cursors ()
|
|
||||||
"The number of cursors (real and fake) in the buffer."
|
|
||||||
(1+ (cl-count-if 'mc/fake-cursor-p
|
|
||||||
(overlays-in (point-min) (point-max)))))
|
|
||||||
|
|
||||||
(defvar mc--this-command nil
|
|
||||||
"Used to store the original command being run.")
|
|
||||||
(make-variable-buffer-local 'mc--this-command)
|
|
||||||
|
|
||||||
(defun mc/make-a-note-of-the-command-being-run ()
|
|
||||||
"Used with pre-command-hook to store the original command being run.
|
|
||||||
Since that cannot be reliably determined in the post-command-hook.
|
|
||||||
|
|
||||||
Specifically, this-original-command isn't always right, because it could have
|
|
||||||
been remapped. And certain modes (cua comes to mind) will change their
|
|
||||||
remapping based on state. So a command that changes the state will afterwards
|
|
||||||
not be recognized through the command-remapping lookup."
|
|
||||||
(unless mc--executing-command-for-fake-cursor
|
|
||||||
(let ((cmd (or (command-remapping this-original-command)
|
|
||||||
this-original-command)))
|
|
||||||
(setq mc--this-command (and (not (eq cmd 'god-mode-self-insert))
|
|
||||||
cmd)))))
|
|
||||||
|
|
||||||
(defun mc/execute-this-command-for-all-cursors ()
|
|
||||||
"Wrap around `mc/execute-this-command-for-all-cursors-1' to protect hook."
|
|
||||||
(condition-case error
|
|
||||||
(mc/execute-this-command-for-all-cursors-1)
|
|
||||||
(error
|
|
||||||
(message "[mc] problem in `mc/execute-this-command-for-all-cursors': %s"
|
|
||||||
(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 ()
|
|
||||||
"Used with post-command-hook to execute supported commands for all cursors.
|
|
||||||
|
|
||||||
It uses two lists of commands to know what to do: the run-once
|
|
||||||
list and the run-for-all list. If a command is in neither of these lists,
|
|
||||||
it will prompt for the proper action and then save that preference.
|
|
||||||
|
|
||||||
Some commands are so unsupported that they are even prevented for
|
|
||||||
the original cursor, to inform about the lack of support."
|
|
||||||
(unless mc--executing-command-for-fake-cursor
|
|
||||||
|
|
||||||
(if (eq 1 (mc/num-cursors)) ;; no fake cursors? disable mc-mode
|
|
||||||
(multiple-cursors-mode 0)
|
|
||||||
(when this-original-command
|
|
||||||
(let ((original-command (or mc--this-command
|
|
||||||
(command-remapping this-original-command)
|
|
||||||
this-original-command)))
|
|
||||||
|
|
||||||
;; skip keyboard macros, since they will generate actual commands that are
|
|
||||||
;; also run in the command loop - we'll handle those later instead.
|
|
||||||
(when (functionp original-command)
|
|
||||||
|
|
||||||
;; 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
|
|
||||||
(if (or (not (symbolp original-command))
|
|
||||||
;; lambda registered by smartrep
|
|
||||||
(string-prefix-p "(" (symbol-name original-command)))
|
|
||||||
(mc/execute-command-for-all-fake-cursors original-command)
|
|
||||||
|
|
||||||
;; smartrep `intern's commands into own obarray to help
|
|
||||||
;; `describe-bindings'. So, let's re-`intern' here to
|
|
||||||
;; make the command comparable by `eq'.
|
|
||||||
(setq original-command (intern (symbol-name original-command)))
|
|
||||||
|
|
||||||
;; otherwise it's a symbol, and we can be more thorough
|
|
||||||
(if (get original-command 'mc--unsupported)
|
|
||||||
(message "%S is not supported with multiple cursors%s"
|
|
||||||
original-command
|
|
||||||
(get original-command 'mc--unsupported))
|
|
||||||
(when (and original-command
|
|
||||||
(not (memq original-command mc--default-cmds-to-run-once))
|
|
||||||
(not (memq original-command mc/cmds-to-run-once))
|
|
||||||
(or mc/always-run-for-all
|
|
||||||
(memq original-command mc--default-cmds-to-run-for-all)
|
|
||||||
(memq original-command mc/cmds-to-run-for-all)
|
|
||||||
(mc/prompt-for-inclusion-in-whitelist original-command)))
|
|
||||||
(mc/execute-command-for-all-fake-cursors original-command))))))))))
|
|
||||||
|
|
||||||
(defun mc/remove-fake-cursors ()
|
|
||||||
"Remove all fake cursors.
|
|
||||||
Do not use to conclude editing with multiple cursors. For that
|
|
||||||
you should disable multiple-cursors-mode."
|
|
||||||
(mc/for-each-fake-cursor
|
|
||||||
(mc/remove-fake-cursor cursor))
|
|
||||||
(when mc--max-cursors-original
|
|
||||||
(setq mc/max-cursors mc--max-cursors-original))
|
|
||||||
(setq mc--max-cursors-original nil))
|
|
||||||
|
|
||||||
(defun mc/keyboard-quit ()
|
|
||||||
"Deactivate mark if there are any active, otherwise exit multiple-cursors-mode."
|
|
||||||
(interactive)
|
|
||||||
(if (not (use-region-p))
|
|
||||||
(multiple-cursors-mode 0)
|
|
||||||
(deactivate-mark)))
|
|
||||||
|
|
||||||
(defun mc/repeat-command ()
|
|
||||||
"Run last command from `command-history' for every fake cursor."
|
|
||||||
(interactive)
|
|
||||||
(when (or mc/always-repeat-command
|
|
||||||
(y-or-n-p (format "[mc] repeat complex command: %s? " (caar command-history))))
|
|
||||||
(mc/execute-command-for-all-fake-cursors
|
|
||||||
(lambda () (interactive)
|
|
||||||
(cl-letf (((symbol-function 'read-from-minibuffer)
|
|
||||||
(lambda (p &optional i k r h d m) (read i))))
|
|
||||||
(repeat-complex-command 0))))))
|
|
||||||
|
|
||||||
(defvar mc/keymap nil
|
|
||||||
"Keymap while multiple cursors are active.
|
|
||||||
Main goal of the keymap is to rebind C-g and <return> to conclude
|
|
||||||
multiple cursors editing.")
|
|
||||||
(unless mc/keymap
|
|
||||||
(setq mc/keymap (make-sparse-keymap))
|
|
||||||
(define-key mc/keymap (kbd "C-g") 'mc/keyboard-quit)
|
|
||||||
(define-key mc/keymap (kbd "<return>") 'multiple-cursors-mode)
|
|
||||||
(define-key mc/keymap (kbd "C-:") 'mc/repeat-command)
|
|
||||||
(when (fboundp 'phi-search)
|
|
||||||
(define-key mc/keymap (kbd "C-s") 'phi-search))
|
|
||||||
(when (fboundp 'phi-search-backward)
|
|
||||||
(define-key mc/keymap (kbd "C-r") 'phi-search-backward)))
|
|
||||||
|
|
||||||
(defun mc--all-equal (list)
|
|
||||||
"Are all the items in LIST equal?"
|
|
||||||
(let ((first (car list))
|
|
||||||
(all-equal t))
|
|
||||||
(while (and all-equal list)
|
|
||||||
(setq all-equal (equal first (car list)))
|
|
||||||
(setq list (cdr list)))
|
|
||||||
all-equal))
|
|
||||||
|
|
||||||
(defun mc--kill-ring-entries ()
|
|
||||||
"Return the latest kill-ring entry for each cursor.
|
|
||||||
The entries are returned in the order they are found in the buffer."
|
|
||||||
(let (entries)
|
|
||||||
(mc/for-each-cursor-ordered
|
|
||||||
(setq entries (cons (car (overlay-get cursor 'kill-ring)) entries)))
|
|
||||||
(reverse entries)))
|
|
||||||
|
|
||||||
(defun mc--maybe-set-killed-rectangle ()
|
|
||||||
"Add the latest kill-ring entry for each cursor to killed-rectangle.
|
|
||||||
So you can paste it in later with `yank-rectangle'."
|
|
||||||
(let ((entries (let (mc/max-cursors) (mc--kill-ring-entries))))
|
|
||||||
(unless (mc--all-equal entries)
|
|
||||||
(setq killed-rectangle entries))))
|
|
||||||
|
|
||||||
(defvar mc/unsupported-minor-modes '(company-mode auto-complete-mode flyspell-mode jedi-mode)
|
|
||||||
"List of minor-modes that does not play well with multiple-cursors.
|
|
||||||
They are temporarily disabled when multiple-cursors are active.")
|
|
||||||
|
|
||||||
(defvar mc/temporarily-disabled-minor-modes nil
|
|
||||||
"The list of temporarily disabled minor-modes.")
|
|
||||||
(make-variable-buffer-local 'mc/temporarily-disabled-minor-modes)
|
|
||||||
|
|
||||||
(defun mc/temporarily-disable-minor-mode (mode)
|
|
||||||
"If MODE is available and turned on, remember that and turn it off."
|
|
||||||
(when (and (boundp mode) (eval mode))
|
|
||||||
(add-to-list 'mc/temporarily-disabled-minor-modes mode)
|
|
||||||
(funcall mode -1)))
|
|
||||||
|
|
||||||
(defun mc/temporarily-disable-unsupported-minor-modes ()
|
|
||||||
(mapc 'mc/temporarily-disable-minor-mode mc/unsupported-minor-modes))
|
|
||||||
|
|
||||||
(defun mc/enable-minor-mode (mode)
|
|
||||||
(funcall mode 1))
|
|
||||||
|
|
||||||
(defun mc/enable-temporarily-disabled-minor-modes ()
|
|
||||||
(mapc 'mc/enable-minor-mode mc/temporarily-disabled-minor-modes)
|
|
||||||
(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)
|
|
||||||
|
|
||||||
;;;###autoload
|
|
||||||
(define-minor-mode multiple-cursors-mode
|
|
||||||
"Mode while multiple cursors are active."
|
|
||||||
nil mc/mode-line mc/keymap
|
|
||||||
(if multiple-cursors-mode
|
|
||||||
(progn
|
|
||||||
(mc/temporarily-disable-unsupported-minor-modes)
|
|
||||||
(add-hook 'pre-command-hook 'mc/make-a-note-of-the-command-being-run nil t)
|
|
||||||
(add-hook 'post-command-hook 'mc/execute-this-command-for-all-cursors t t)
|
|
||||||
(run-hooks 'multiple-cursors-mode-enabled-hook))
|
|
||||||
(remove-hook 'post-command-hook 'mc/execute-this-command-for-all-cursors t)
|
|
||||||
(remove-hook 'pre-command-hook 'mc/make-a-note-of-the-command-being-run t)
|
|
||||||
(setq mc--this-command nil)
|
|
||||||
(mc--maybe-set-killed-rectangle)
|
|
||||||
(mc/remove-fake-cursors)
|
|
||||||
(mc/enable-temporarily-disabled-minor-modes)
|
|
||||||
(run-hooks 'multiple-cursors-mode-disabled-hook)))
|
|
||||||
|
|
||||||
(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)
|
|
||||||
"Adds command to list of unsupported commands and prevents it
|
|
||||||
from being executed if in multiple-cursors-mode."
|
|
||||||
`(progn
|
|
||||||
(put (quote ,cmd) 'mc--unsupported ,msg)
|
|
||||||
(defadvice ,cmd (around unsupported-advice activate)
|
|
||||||
"command isn't supported with multiple cursors"
|
|
||||||
(unless (and multiple-cursors-mode (called-interactively-p 'any))
|
|
||||||
ad-do-it))))
|
|
||||||
|
|
||||||
;; Commands that does not work with multiple-cursors
|
|
||||||
(unsupported-cmd isearch-forward ". Feel free to add a compatible version.")
|
|
||||||
(unsupported-cmd isearch-backward ". Feel free to add a compatible version.")
|
|
||||||
|
|
||||||
;; Make sure pastes from other programs are added to all kill-rings when yanking
|
|
||||||
(defadvice current-kill (before interprogram-paste-for-all-cursors
|
|
||||||
(n &optional do-not-move) activate)
|
|
||||||
(let ((interprogram-paste (and (= n 0)
|
|
||||||
interprogram-paste-function
|
|
||||||
(funcall interprogram-paste-function))))
|
|
||||||
(when interprogram-paste
|
|
||||||
;; Add interprogram-paste to normal kill ring, just
|
|
||||||
;; like current-kill usually does for itself.
|
|
||||||
;; We have to do the work for it tho, since the funcall only returns
|
|
||||||
;; something once. It is not a pure function.
|
|
||||||
(let ((interprogram-cut-function nil))
|
|
||||||
(if (listp interprogram-paste)
|
|
||||||
(mapc 'kill-new (nreverse interprogram-paste))
|
|
||||||
(kill-new interprogram-paste))
|
|
||||||
;; And then add interprogram-paste to the kill-rings
|
|
||||||
;; of all the other cursors too.
|
|
||||||
(mc/for-each-fake-cursor
|
|
||||||
(let ((kill-ring (overlay-get cursor 'kill-ring))
|
|
||||||
(kill-ring-yank-pointer (overlay-get cursor 'kill-ring-yank-pointer)))
|
|
||||||
(if (listp interprogram-paste)
|
|
||||||
(mapc 'kill-new (nreverse interprogram-paste))
|
|
||||||
(kill-new interprogram-paste))
|
|
||||||
(overlay-put cursor 'kill-ring kill-ring)
|
|
||||||
(overlay-put cursor 'kill-ring-yank-pointer kill-ring-yank-pointer)))))))
|
|
||||||
|
|
||||||
(defcustom mc/list-file (locate-user-emacs-file ".mc-lists.el")
|
|
||||||
"The position of the file that keeps track of your preferences
|
|
||||||
for running commands with multiple cursors."
|
|
||||||
:type 'file
|
|
||||||
:group 'multiple-cursors)
|
|
||||||
|
|
||||||
(defun mc/dump-list (list-symbol)
|
|
||||||
"Insert (setq 'LIST-SYMBOL LIST-VALUE) to current buffer."
|
|
||||||
(cl-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 ()
|
|
||||||
"Saves preferences for running commands with multiple cursors to `mc/list-file'"
|
|
||||||
(with-temp-file mc/list-file
|
|
||||||
(emacs-lisp-mode)
|
|
||||||
(insert ";; This file is automatically generated by the multiple-cursors extension.")
|
|
||||||
(newline)
|
|
||||||
(insert ";; It keeps track of your preferences for running commands with multiple cursors.")
|
|
||||||
(newline)
|
|
||||||
(newline)
|
|
||||||
(mc/dump-list 'mc/cmds-to-run-for-all)
|
|
||||||
(newline)
|
|
||||||
(mc/dump-list 'mc/cmds-to-run-once)))
|
|
||||||
|
|
||||||
(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.")
|
||||||
|
|
||||||
@@ -691,6 +455,8 @@ for running commands with multiple cursors."
|
|||||||
redo
|
redo
|
||||||
undo-tree-undo
|
undo-tree-undo
|
||||||
undo-tree-redo
|
undo-tree-redo
|
||||||
|
undo-fu-only-undo
|
||||||
|
undo-fu-only-redo
|
||||||
universal-argument
|
universal-argument
|
||||||
universal-argument-more
|
universal-argument-more
|
||||||
universal-argument-other-key
|
universal-argument-other-key
|
||||||
@@ -723,6 +489,9 @@ for running commands with multiple cursors."
|
|||||||
windmove-down
|
windmove-down
|
||||||
repeat-complex-command))
|
repeat-complex-command))
|
||||||
|
|
||||||
|
(defvar mc/cmds-to-run-for-all nil
|
||||||
|
"Commands to run for all cursors in multiple-cursors-mode")
|
||||||
|
|
||||||
(defvar mc--default-cmds-to-run-for-all nil
|
(defvar mc--default-cmds-to-run-for-all nil
|
||||||
"Default set of commands that should be mirrored by all cursors")
|
"Default set of commands that should be mirrored by all cursors")
|
||||||
|
|
||||||
@@ -803,14 +572,339 @@ for running commands with multiple cursors."
|
|||||||
smart-up
|
smart-up
|
||||||
smart-down))
|
smart-down))
|
||||||
|
|
||||||
(defvar mc/cmds-to-run-for-all nil
|
(defun mc/prompt-for-inclusion-in-whitelist (original-command)
|
||||||
"Commands to run for all cursors in multiple-cursors-mode")
|
"Asks the user, then adds the command either to the once-list or the all-list."
|
||||||
|
(let ((all-p (y-or-n-p (format "Do %S for all cursors?" original-command))))
|
||||||
|
(if all-p
|
||||||
|
(add-to-list 'mc/cmds-to-run-for-all original-command)
|
||||||
|
(add-to-list 'mc/cmds-to-run-once original-command))
|
||||||
|
(mc/save-lists)
|
||||||
|
all-p))
|
||||||
|
|
||||||
;; load, but no errors if it does not exist yet please, and no message
|
(defun mc/num-cursors ()
|
||||||
;; while loading
|
"The number of cursors (real and fake) in the buffer."
|
||||||
|
(1+ (cl-count-if #'mc/fake-cursor-p
|
||||||
|
(overlays-in (point-min) (point-max)))))
|
||||||
|
|
||||||
|
(defvar mc--this-command nil
|
||||||
|
"Used to store the original command being run.")
|
||||||
|
(make-variable-buffer-local 'mc--this-command)
|
||||||
|
|
||||||
|
(defun mc/make-a-note-of-the-command-being-run ()
|
||||||
|
"Used with pre-command-hook to store the original command being run.
|
||||||
|
Since that cannot be reliably determined in the post-command-hook.
|
||||||
|
|
||||||
|
Specifically, this-original-command isn't always right, because it could have
|
||||||
|
been remapped. And certain modes (cua comes to mind) will change their
|
||||||
|
remapping based on state. So a command that changes the state will afterwards
|
||||||
|
not be recognized through the command-remapping lookup."
|
||||||
|
(unless mc--executing-command-for-fake-cursor
|
||||||
|
(let ((cmd (or (command-remapping this-original-command)
|
||||||
|
this-original-command)))
|
||||||
|
(setq mc--this-command (and (not (eq cmd 'god-mode-self-insert))
|
||||||
|
cmd)))))
|
||||||
|
|
||||||
|
(defun mc/execute-this-command-for-all-cursors ()
|
||||||
|
"Wrap around `mc/execute-this-command-for-all-cursors-1' to protect hook."
|
||||||
|
(condition-case error
|
||||||
|
(mc/execute-this-command-for-all-cursors-1)
|
||||||
|
(error
|
||||||
|
(message "[mc] problem in `mc/execute-this-command-for-all-cursors': %s"
|
||||||
|
(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.
|
||||||
|
(advice-add 'execute-kbd-macro :around #'mc--skip-fake-cursors)
|
||||||
|
(defun mc--skip-fake-cursors (orig-fun &rest args)
|
||||||
|
(unless mc--executing-command-for-fake-cursor
|
||||||
|
(apply orig-fun args)))
|
||||||
|
|
||||||
|
(defun mc/execute-this-command-for-all-cursors-1 ()
|
||||||
|
"Used with post-command-hook to execute supported commands for all cursors.
|
||||||
|
|
||||||
|
It uses two lists of commands to know what to do: the run-once
|
||||||
|
list and the run-for-all list. If a command is in neither of these lists,
|
||||||
|
it will prompt for the proper action and then save that preference.
|
||||||
|
|
||||||
|
Some commands are so unsupported that they are even prevented for
|
||||||
|
the original cursor, to inform about the lack of support."
|
||||||
|
(unless mc--executing-command-for-fake-cursor
|
||||||
|
|
||||||
|
(if (eq 1 (mc/num-cursors)) ;; no fake cursors? disable mc-mode
|
||||||
|
(mc/disable-multiple-cursors-mode)
|
||||||
|
(when this-original-command
|
||||||
|
(let ((original-command (or mc--this-command
|
||||||
|
(command-remapping this-original-command)
|
||||||
|
this-original-command)))
|
||||||
|
|
||||||
|
;; skip keyboard macros, since they will generate actual commands that are
|
||||||
|
;; also run in the command loop - we'll handle those later instead.
|
||||||
|
(when (functionp original-command)
|
||||||
|
|
||||||
|
;; 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
|
||||||
|
(if (or (not (symbolp original-command))
|
||||||
|
;; lambda registered by smartrep
|
||||||
|
(string-prefix-p "(" (symbol-name original-command)))
|
||||||
|
(mc/execute-command-for-all-fake-cursors original-command)
|
||||||
|
|
||||||
|
;; smartrep `intern's commands into own obarray to help
|
||||||
|
;; `describe-bindings'. So, let's re-`intern' here to
|
||||||
|
;; make the command comparable by `eq'.
|
||||||
|
(setq original-command (intern (symbol-name original-command)))
|
||||||
|
|
||||||
|
;; otherwise it's a symbol, and we can be more thorough
|
||||||
|
(if (get original-command 'mc--unsupported)
|
||||||
|
(message "%S is not supported with multiple cursors%s"
|
||||||
|
original-command
|
||||||
|
(get original-command 'mc--unsupported))
|
||||||
|
|
||||||
|
;; lazy-load the user's list file
|
||||||
|
(mc/load-lists)
|
||||||
|
|
||||||
|
(when (and original-command
|
||||||
|
(not (memq original-command mc--default-cmds-to-run-once))
|
||||||
|
(not (memq original-command mc/cmds-to-run-once))
|
||||||
|
(or mc/always-run-for-all
|
||||||
|
(memq original-command mc--default-cmds-to-run-for-all)
|
||||||
|
(memq original-command mc/cmds-to-run-for-all)
|
||||||
|
(mc/prompt-for-inclusion-in-whitelist original-command)))
|
||||||
|
(mc/execute-command-for-all-fake-cursors original-command))))))))))
|
||||||
|
|
||||||
|
(defun mc/remove-fake-cursors ()
|
||||||
|
"Remove all fake cursors.
|
||||||
|
Do not use to conclude editing with multiple cursors. For that
|
||||||
|
you should disable multiple-cursors-mode."
|
||||||
|
(mc/for-each-fake-cursor
|
||||||
|
(mc/remove-fake-cursor cursor))
|
||||||
|
(when mc--max-cursors-original
|
||||||
|
(setq mc/max-cursors mc--max-cursors-original))
|
||||||
|
(setq mc--max-cursors-original nil))
|
||||||
|
|
||||||
|
(defun mc/keyboard-quit ()
|
||||||
|
"Deactivate mark if there are any active, otherwise exit multiple-cursors-mode."
|
||||||
|
(interactive)
|
||||||
|
(if (not (use-region-p))
|
||||||
|
(mc/disable-multiple-cursors-mode)
|
||||||
|
(deactivate-mark)))
|
||||||
|
|
||||||
|
(defun mc/repeat-command ()
|
||||||
|
"Run last command from `command-history' for every fake cursor."
|
||||||
|
(interactive)
|
||||||
|
(when (or mc/always-repeat-command
|
||||||
|
(y-or-n-p (format "[mc] repeat complex command: %s? " (caar command-history))))
|
||||||
|
(mc/execute-command-for-all-fake-cursors
|
||||||
|
(lambda () (interactive)
|
||||||
|
(cl-letf (((symbol-function 'read-from-minibuffer)
|
||||||
|
(lambda (_p &optional i &rest _) (read i))))
|
||||||
|
(repeat-complex-command 0))))))
|
||||||
|
|
||||||
|
(defvar mc/keymap nil
|
||||||
|
"Keymap while multiple cursors are active.
|
||||||
|
Main goal of the keymap is to rebind C-g and <return> to conclude
|
||||||
|
multiple cursors editing.")
|
||||||
|
(unless mc/keymap
|
||||||
|
(setq mc/keymap (make-sparse-keymap))
|
||||||
|
(define-key mc/keymap (kbd "C-g") #'mc/keyboard-quit)
|
||||||
|
(define-key mc/keymap (kbd "<return>") #'multiple-cursors-mode)
|
||||||
|
(define-key mc/keymap (kbd "C-:") #'mc/repeat-command)
|
||||||
|
(when (fboundp 'phi-search)
|
||||||
|
(define-key mc/keymap (kbd "C-s") #'phi-search))
|
||||||
|
(when (fboundp 'phi-search-backward)
|
||||||
|
(define-key mc/keymap (kbd "C-r") #'phi-search-backward)))
|
||||||
|
|
||||||
|
(defun mc--all-equal (list)
|
||||||
|
"Are all the items in LIST equal?"
|
||||||
|
(let ((first (car list))
|
||||||
|
(all-equal t))
|
||||||
|
(while (and all-equal list)
|
||||||
|
(setq all-equal (equal first (car list)))
|
||||||
|
(setq list (cdr list)))
|
||||||
|
all-equal))
|
||||||
|
|
||||||
|
(defun mc--kill-ring-entries ()
|
||||||
|
"Return the latest kill-ring entry for each cursor.
|
||||||
|
The entries are returned in the order they are found in the buffer."
|
||||||
|
(let (entries)
|
||||||
|
(mc/for-each-cursor-ordered
|
||||||
|
(setq entries (cons (car (overlay-get cursor 'kill-ring)) entries)))
|
||||||
|
(reverse entries)))
|
||||||
|
|
||||||
|
(defun mc--maybe-set-killed-rectangle ()
|
||||||
|
"Add the latest kill-ring entry for each cursor to killed-rectangle.
|
||||||
|
So you can paste it in later with `yank-rectangle'."
|
||||||
|
(let ((entries (let (mc/max-cursors) (mc--kill-ring-entries))))
|
||||||
|
(unless (mc--all-equal entries)
|
||||||
|
(setq killed-rectangle entries))))
|
||||||
|
|
||||||
|
(defvar mc/unsupported-minor-modes '(company-mode auto-complete-mode flyspell-mode jedi-mode)
|
||||||
|
"List of minor-modes that does not play well with multiple-cursors.
|
||||||
|
They are temporarily disabled when multiple-cursors are active.")
|
||||||
|
|
||||||
|
(defvar mc/temporarily-disabled-minor-modes nil
|
||||||
|
"The list of temporarily disabled minor-modes.")
|
||||||
|
(make-variable-buffer-local 'mc/temporarily-disabled-minor-modes)
|
||||||
|
|
||||||
|
(defun mc/temporarily-disable-minor-mode (mode)
|
||||||
|
"If MODE is available and turned on, remember that and turn it off."
|
||||||
|
(when (and (boundp mode) (symbol-value mode))
|
||||||
|
(add-to-list 'mc/temporarily-disabled-minor-modes mode)
|
||||||
|
(funcall mode -1)))
|
||||||
|
|
||||||
|
(defun mc/temporarily-disable-unsupported-minor-modes ()
|
||||||
|
(mapc #'mc/temporarily-disable-minor-mode mc/unsupported-minor-modes))
|
||||||
|
|
||||||
|
(defun mc/enable-minor-mode (mode)
|
||||||
|
(funcall mode 1))
|
||||||
|
|
||||||
|
(defun mc/enable-temporarily-disabled-minor-modes ()
|
||||||
|
(mapc #'mc/enable-minor-mode mc/temporarily-disabled-minor-modes)
|
||||||
|
(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."
|
||||||
|
:type '(sexp)
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
(put 'mc/mode-line 'risky-local-variable t)
|
||||||
|
|
||||||
|
;;;###autoload
|
||||||
|
(define-minor-mode multiple-cursors-mode
|
||||||
|
"Mode while multiple cursors are active."
|
||||||
|
:init-value nil
|
||||||
|
:lighter mc/mode-line
|
||||||
|
:keymap mc/keymap
|
||||||
|
(if multiple-cursors-mode
|
||||||
|
(progn
|
||||||
|
(mc/temporarily-disable-unsupported-minor-modes)
|
||||||
|
(add-hook 'pre-command-hook #'mc/make-a-note-of-the-command-being-run nil t)
|
||||||
|
(add-hook 'post-command-hook #'mc/execute-this-command-for-all-cursors t t)
|
||||||
|
(run-hooks 'multiple-cursors-mode-enabled-hook))
|
||||||
|
(remove-hook 'post-command-hook #'mc/execute-this-command-for-all-cursors t)
|
||||||
|
(remove-hook 'pre-command-hook #'mc/make-a-note-of-the-command-being-run t)
|
||||||
|
(setq mc--this-command nil)
|
||||||
|
(mc--maybe-set-killed-rectangle)
|
||||||
|
(mc/remove-fake-cursors)
|
||||||
|
(mc/enable-temporarily-disabled-minor-modes)
|
||||||
|
(run-hooks 'multiple-cursors-mode-disabled-hook)))
|
||||||
|
|
||||||
|
(defun mc/disable-multiple-cursors-mode ()
|
||||||
|
"Disable multiple-cursors-mode and run the corresponding hook."
|
||||||
|
(multiple-cursors-mode 0)
|
||||||
|
(run-hooks 'multiple-cursors-mode-disabled-hook))
|
||||||
|
|
||||||
|
(add-hook 'after-revert-hook #'mc/disable-multiple-cursors-mode)
|
||||||
|
|
||||||
|
(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)
|
||||||
|
(mc/disable-multiple-cursors-mode)))
|
||||||
|
|
||||||
|
(defun mc--unsupported-advice (orig-fun &rest args)
|
||||||
|
"command isn't supported with multiple cursors."
|
||||||
|
(unless (and multiple-cursors-mode (called-interactively-p 'any))
|
||||||
|
(apply orig-fun args)))
|
||||||
|
|
||||||
|
(defmacro unsupported-cmd (cmd msg)
|
||||||
|
"Adds command to list of unsupported commands and prevents it
|
||||||
|
from being executed if in multiple-cursors-mode."
|
||||||
|
`(progn
|
||||||
|
(put ',cmd 'mc--unsupported ,msg)
|
||||||
|
(advice-add ',cmd :around #'mc--unsupported-advice)))
|
||||||
|
|
||||||
|
;; Commands that does not work with multiple-cursors
|
||||||
|
(unsupported-cmd isearch-forward ". Feel free to add a compatible version.")
|
||||||
|
(unsupported-cmd isearch-backward ". Feel free to add a compatible version.")
|
||||||
|
|
||||||
|
;; Make sure pastes from other programs are added to all kill-rings when yanking
|
||||||
|
(advice-add 'current-kill :before #'mc--interprogram-paste-for-all-cursors)
|
||||||
|
(defun mc--interprogram-paste-for-all-cursors (n &rest _)
|
||||||
|
;; FIXME: Shouldn't we check `multiple-cursors-mode' or something?
|
||||||
|
(let ((interprogram-paste (and (= n 0)
|
||||||
|
interprogram-paste-function
|
||||||
|
(funcall interprogram-paste-function))))
|
||||||
|
(when interprogram-paste
|
||||||
|
;; Add interprogram-paste to normal kill ring, just
|
||||||
|
;; like current-kill usually does for itself.
|
||||||
|
;; We have to do the work for it though, since the funcall only returns
|
||||||
|
;; something once. It is not a pure function.
|
||||||
|
(let ((interprogram-cut-function nil))
|
||||||
|
(if (listp interprogram-paste)
|
||||||
|
(mapc #'kill-new (nreverse interprogram-paste))
|
||||||
|
(kill-new interprogram-paste))
|
||||||
|
;; And then add interprogram-paste to the kill-rings
|
||||||
|
;; of all the other cursors too.
|
||||||
|
(mc/for-each-fake-cursor
|
||||||
|
(let ((kill-ring (overlay-get cursor 'kill-ring))
|
||||||
|
(kill-ring-yank-pointer (overlay-get cursor 'kill-ring-yank-pointer)))
|
||||||
|
(if (listp interprogram-paste)
|
||||||
|
(mapc #'kill-new (nreverse interprogram-paste))
|
||||||
|
(kill-new interprogram-paste))
|
||||||
|
(overlay-put cursor 'kill-ring kill-ring)
|
||||||
|
(overlay-put cursor 'kill-ring-yank-pointer kill-ring-yank-pointer)))))))
|
||||||
|
|
||||||
|
(advice-add 'execute-extended-command :after #'mc--execute-extended-command-for-all-cursors)
|
||||||
|
(defun mc--execute-extended-command-for-all-cursors (&rest _)
|
||||||
|
(when multiple-cursors-mode
|
||||||
|
(unless (or mc/always-run-for-all
|
||||||
|
(not (symbolp this-command))
|
||||||
|
(memq this-command mc/cmds-to-run-for-all)
|
||||||
|
(memq this-command mc/cmds-to-run-once)
|
||||||
|
(memq this-command mc--default-cmds-to-run-for-all)
|
||||||
|
(memq this-command mc--default-cmds-to-run-once))
|
||||||
|
(mc/prompt-for-inclusion-in-whitelist this-command))
|
||||||
|
(when (or mc/always-run-for-all
|
||||||
|
(memq this-command mc/cmds-to-run-for-all)
|
||||||
|
(memq this-command mc--default-cmds-to-run-for-all))
|
||||||
|
(mc/execute-command-for-all-fake-cursors this-command))))
|
||||||
|
|
||||||
|
(defcustom mc/list-file (locate-user-emacs-file ".mc-lists.el")
|
||||||
|
"The position of the file that keeps track of your preferences
|
||||||
|
for running commands with multiple cursors."
|
||||||
|
:type 'file
|
||||||
|
:group 'multiple-cursors)
|
||||||
|
|
||||||
|
(defvar mc--list-file-loaded nil
|
||||||
|
"Whether the list file has already been loaded.")
|
||||||
|
|
||||||
|
(defun mc/load-lists ()
|
||||||
|
"Loads preferences for running commands with multiple cursors from `mc/list-file'"
|
||||||
|
(unless mc--list-file-loaded
|
||||||
(load mc/list-file 'noerror 'nomessage)
|
(load mc/list-file 'noerror 'nomessage)
|
||||||
|
(setq mc--list-file-loaded t)))
|
||||||
|
|
||||||
|
(defun mc/dump-list (list-symbol)
|
||||||
|
"Insert (setq LIST-SYMBOL LIST-VALUE) to current buffer."
|
||||||
|
(cl-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 ()
|
||||||
|
"Saves preferences for running commands with multiple cursors to `mc/list-file'"
|
||||||
|
(with-temp-file mc/list-file
|
||||||
|
(emacs-lisp-mode)
|
||||||
|
(when (> emacs-major-version 30)
|
||||||
|
(insert ";; -*- lexical-binding: t; -*-\n"))
|
||||||
|
(insert ";; This file is automatically generated by the multiple-cursors extension.\n")
|
||||||
|
(insert ";; It keeps track of your preferences for running commands with multiple cursors.\n\n")
|
||||||
|
(mc/dump-list 'mc/cmds-to-run-for-all)
|
||||||
|
(newline)
|
||||||
|
(mc/dump-list 'mc/cmds-to-run-once)))
|
||||||
|
|
||||||
(provide 'multiple-cursors-core)
|
(provide 'multiple-cursors-core)
|
||||||
|
(require 'mc-cycle-cursors)
|
||||||
|
(require 'mc-hide-unmatched-lines-mode)
|
||||||
|
|
||||||
;; Local Variables:
|
;; Local Variables:
|
||||||
;; coding: utf-8
|
;; coding: utf-8
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
(define-package "multiple-cursors" "1.3.0"
|
|
||||||
"Multiple cursors for Emacs."
|
|
||||||
'((cl-lib "0.5")))
|
|
||||||
+7
-8
@@ -1,10 +1,12 @@
|
|||||||
;;; multiple-cursors.el --- Multiple cursors for emacs.
|
;;; multiple-cursors.el --- Multiple cursors for Emacs -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||||
;; Version: 1.4.0
|
;; Package-Version: 1.5.0
|
||||||
|
;; Package-Requires: ((emacs "24.4") (cl-lib "0.5"))
|
||||||
;; Keywords: editing cursors
|
;; Keywords: editing cursors
|
||||||
|
;; Homepage: https://github.com/magnars/multiple-cursors.el
|
||||||
|
|
||||||
;; This program is free software; you can redistribute it and/or modify
|
;; 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
|
;; it under the terms of the GNU General Public License as published by
|
||||||
@@ -22,7 +24,7 @@
|
|||||||
;;; Commentary:
|
;;; Commentary:
|
||||||
|
|
||||||
;; 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 though, I've been using it since 2011 with
|
||||||
;; great success and much merriment.
|
;; great success and much merriment.
|
||||||
|
|
||||||
;; ## Basic usage
|
;; ## Basic usage
|
||||||
@@ -68,7 +70,7 @@
|
|||||||
;; - `mc/mark-previous-like-this`: Adds a cursor and region at the next part of the buffer backwards that matches the current region.
|
;; - `mc/mark-previous-like-this`: Adds a cursor and region at the next part of the buffer backwards that matches the current region.
|
||||||
;; - `mc/mark-previous-word-like-this`: Like `mc/mark-previous-like-this` but only for whole words.
|
;; - `mc/mark-previous-word-like-this`: Like `mc/mark-previous-like-this` but only for whole words.
|
||||||
;; - `mc/mark-previous-symbol-like-this`: Like `mc/mark-previous-like-this` but only for whole symbols.
|
;; - `mc/mark-previous-symbol-like-this`: Like `mc/mark-previous-like-this` but only for whole symbols.
|
||||||
;; - `mc/mark-more-like-this-extended`: Use arrow keys to quickly mark/skip next/previous occurances.
|
;; - `mc/mark-more-like-this-extended`: Use arrow keys to quickly mark/skip next/previous occurrences.
|
||||||
;; - `mc/add-cursor-on-click`: Bind to a mouse event to add cursors by clicking. See tips-section.
|
;; - `mc/add-cursor-on-click`: Bind to a mouse event to add cursors by clicking. See tips-section.
|
||||||
|
|
||||||
;; ### Mark many occurrences
|
;; ### Mark many occurrences
|
||||||
@@ -105,7 +107,7 @@
|
|||||||
;;
|
;;
|
||||||
;; - Try pressing `mc/mark-next-like-this-word` or
|
;; - Try pressing `mc/mark-next-like-this-word` or
|
||||||
;; `mc/mark-next-like-this-symbol` with no region selected. It will
|
;; `mc/mark-next-like-this-symbol` with no region selected. It will
|
||||||
;; mark the symbol and add a cursor at the next occurance
|
;; mark the symbol and add a cursor at the next occurrence
|
||||||
;;
|
;;
|
||||||
;; - Try pressing `mc/mark-all-like-this-dwim` on a tagname in html-mode.
|
;; - Try pressing `mc/mark-all-like-this-dwim` on a tagname in html-mode.
|
||||||
;;
|
;;
|
||||||
@@ -152,7 +154,6 @@
|
|||||||
|
|
||||||
;; * 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.
|
|
||||||
;; * 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.
|
||||||
@@ -191,12 +192,10 @@
|
|||||||
:group 'editing)
|
:group 'editing)
|
||||||
|
|
||||||
(require 'mc-edit-lines)
|
(require 'mc-edit-lines)
|
||||||
(require 'mc-cycle-cursors)
|
|
||||||
(require 'mc-mark-more)
|
(require 'mc-mark-more)
|
||||||
(require 'mc-mark-pop)
|
(require 'mc-mark-pop)
|
||||||
(require 'rectangular-region-mode)
|
(require 'rectangular-region-mode)
|
||||||
(require 'mc-separate-operations)
|
(require 'mc-separate-operations)
|
||||||
(require 'mc-hide-unmatched-lines-mode)
|
|
||||||
|
|
||||||
(provide 'multiple-cursors)
|
(provide 'multiple-cursors)
|
||||||
|
|
||||||
|
|||||||
+25
-23
@@ -1,4 +1,4 @@
|
|||||||
;;; rectangular-region-mode.el
|
;;; rectangular-region-mode.el -*- lexical-binding: t; -*-
|
||||||
|
|
||||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||||
|
|
||||||
@@ -35,8 +35,8 @@
|
|||||||
(defvar rectangular-region-mode-map (make-sparse-keymap)
|
(defvar rectangular-region-mode-map (make-sparse-keymap)
|
||||||
"Keymap for rectangular region is mainly for rebinding C-g")
|
"Keymap for rectangular region is mainly for rebinding C-g")
|
||||||
|
|
||||||
(define-key rectangular-region-mode-map (kbd "C-g") 'rrm/keyboard-quit)
|
(define-key rectangular-region-mode-map (kbd "C-g") #'rrm/keyboard-quit)
|
||||||
(define-key rectangular-region-mode-map (kbd "<return>") 'rrm/switch-to-multiple-cursors)
|
(define-key rectangular-region-mode-map (kbd "<return>") #'rrm/switch-to-multiple-cursors)
|
||||||
|
|
||||||
(defvar rectangular-region-mode nil)
|
(defvar rectangular-region-mode nil)
|
||||||
|
|
||||||
@@ -52,8 +52,9 @@
|
|||||||
(defun set-rectangular-region-anchor ()
|
(defun set-rectangular-region-anchor ()
|
||||||
"Anchors the rectangular region at point.
|
"Anchors the rectangular region at point.
|
||||||
|
|
||||||
Think of this one as `set-mark' except you're marking a rectangular region. It is
|
Think of this one as `set-mark' except you're marking a
|
||||||
an exceedingly quick way of adding multiple cursors to multiple lines."
|
rectangular region. It is an exceedingly quick way of adding
|
||||||
|
multiple cursors to multiple lines."
|
||||||
(interactive)
|
(interactive)
|
||||||
(set-marker rrm/anchor (point))
|
(set-marker rrm/anchor (point))
|
||||||
(push-mark (point))
|
(push-mark (point))
|
||||||
@@ -70,22 +71,23 @@ an exceedingly quick way of adding multiple cursors to multiple lines."
|
|||||||
(defun rrm/repaint ()
|
(defun rrm/repaint ()
|
||||||
"Start from the anchor and draw a rectangle between it and point."
|
"Start from the anchor and draw a rectangle between it and point."
|
||||||
(if (not rectangular-region-mode)
|
(if (not rectangular-region-mode)
|
||||||
(remove-hook 'post-command-hook 'rrm/repaint t)
|
(remove-hook 'post-command-hook #'rrm/repaint t)
|
||||||
;; else
|
;; else
|
||||||
|
(defvar annoying-arrows-mode)
|
||||||
(rrm/remove-rectangular-region-overlays)
|
(rrm/remove-rectangular-region-overlays)
|
||||||
(let* ((annoying-arrows-mode nil)
|
(let* ((annoying-arrows-mode nil)
|
||||||
(point-column (current-column))
|
(point-column (current-column))
|
||||||
(point-line (line-number-at-pos))
|
(point-line (mc/line-number-at-pos))
|
||||||
(anchor-column (save-excursion (goto-char rrm/anchor) (current-column)))
|
(anchor-column (save-excursion (goto-char rrm/anchor) (current-column)))
|
||||||
(anchor-line (save-excursion (goto-char rrm/anchor) (line-number-at-pos)))
|
(anchor-line (save-excursion (goto-char rrm/anchor) (mc/line-number-at-pos)))
|
||||||
(left-column (if (< point-column anchor-column) point-column anchor-column))
|
;; (left-column (if (< point-column anchor-column) point-column anchor-column))
|
||||||
(right-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)))
|
(navigation-step (if (< point-line anchor-line) 1 -1)))
|
||||||
(move-to-column anchor-column)
|
(move-to-column anchor-column)
|
||||||
(set-mark (point))
|
(set-mark (point))
|
||||||
(move-to-column point-column)
|
(move-to-column point-column)
|
||||||
(mc/save-excursion
|
(mc/save-excursion
|
||||||
(while (not (= anchor-line (line-number-at-pos)))
|
(while (not (= anchor-line (mc/line-number-at-pos)))
|
||||||
(forward-line navigation-step)
|
(forward-line navigation-step)
|
||||||
(move-to-column anchor-column)
|
(move-to-column anchor-column)
|
||||||
(when (= anchor-column (current-column))
|
(when (= anchor-column (current-column))
|
||||||
@@ -94,30 +96,30 @@ an exceedingly quick way of adding multiple cursors to multiple lines."
|
|||||||
(when (= point-column (current-column))
|
(when (= point-column (current-column))
|
||||||
(mc/create-fake-cursor-at-point))))))))
|
(mc/create-fake-cursor-at-point))))))))
|
||||||
|
|
||||||
(defun rrm/switch-to-multiple-cursors (&rest forms)
|
(defun rrm/switch-to-multiple-cursors (&rest _)
|
||||||
"Switch from rectangular-region-mode to multiple-cursors-mode."
|
"Switch from `rectangular-region-mode' to `multiple-cursors-mode'."
|
||||||
(interactive)
|
(interactive)
|
||||||
(rectangular-region-mode 0)
|
(rectangular-region-mode 0)
|
||||||
(multiple-cursors-mode 1))
|
(multiple-cursors-mode 1))
|
||||||
|
|
||||||
(defadvice er/expand-region (before switch-from-rrm-to-mc activate)
|
(advice-add 'er/expand-region :before #'rrm//switch-from-rrm-to-mc)
|
||||||
(when rectangular-region-mode
|
(advice-add 'kill-ring-save :before #'rrm//switch-from-rrm-to-mc)
|
||||||
(rrm/switch-to-multiple-cursors)))
|
(defun rrm//switch-from-rrm-to-mc (&rest _)
|
||||||
|
|
||||||
(defadvice kill-ring-save (before switch-from-rrm-to-mc activate)
|
|
||||||
(when rectangular-region-mode
|
(when rectangular-region-mode
|
||||||
(rrm/switch-to-multiple-cursors)))
|
(rrm/switch-to-multiple-cursors)))
|
||||||
|
|
||||||
;;;###autoload
|
;;;###autoload
|
||||||
(define-minor-mode rectangular-region-mode
|
(define-minor-mode rectangular-region-mode
|
||||||
"A mode for creating a rectangular region to edit"
|
"A mode for creating a rectangular region to edit"
|
||||||
nil " rr" rectangular-region-mode-map
|
:init-value nil
|
||||||
|
:lighter " rr"
|
||||||
|
:keymap rectangular-region-mode-map
|
||||||
(if rectangular-region-mode
|
(if rectangular-region-mode
|
||||||
(progn
|
(progn
|
||||||
(add-hook 'after-change-functions 'rrm/switch-to-multiple-cursors t t)
|
(add-hook 'after-change-functions #'rrm/switch-to-multiple-cursors t t)
|
||||||
(add-hook 'post-command-hook 'rrm/repaint t t))
|
(add-hook 'post-command-hook #'rrm/repaint t t))
|
||||||
(remove-hook 'after-change-functions 'rrm/switch-to-multiple-cursors t)
|
(remove-hook 'after-change-functions #'rrm/switch-to-multiple-cursors t)
|
||||||
(remove-hook 'post-command-hook 'rrm/repaint t)
|
(remove-hook 'post-command-hook #'rrm/repaint t)
|
||||||
(set-marker rrm/anchor nil)))
|
(set-marker rrm/anchor nil)))
|
||||||
|
|
||||||
(provide 'rectangular-region-mode)
|
(provide 'rectangular-region-mode)
|
||||||
|
|||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/bin/sh -e
|
|
||||||
|
|
||||||
cd "$(dirname "$0")"
|
|
||||||
|
|
||||||
ECUKES_EMACS=${EMACS:-$(which emacs)}
|
|
||||||
export ECUKES_EMACS
|
|
||||||
|
|
||||||
echo "*** Emacs version ***"
|
|
||||||
echo "ECUKES_EMACS = $ECUKES_EMACS"
|
|
||||||
"$ECUKES_EMACS" --version
|
|
||||||
echo
|
|
||||||
|
|
||||||
exec ./run-tests.sh $TAGS
|
|
||||||
Reference in New Issue
Block a user