55 Commits

Author SHA1 Message Date
Gene Goykhman 94b8b07a4b Remove redundant check of use-region-p that is already done in use-region-beginning/end 2026-04-19 11:31:13 +02:00
Gene Goykhman 6f984c6e1d Also update furthest-cursor-before-point for transient-mark-mode inactive 2026-04-10 15:31:43 +02:00
Gene Goykhman 47c27f1e19 Check use-region-p rather than mark-active to better support
transient-mark-mode disabled
2026-04-10 15:31:43 +02:00
Stefan Monnier ddd677091a Avoid deprecated ELisp features
Activate `lexical-binding` in a few more files.
Use `advice-add` rather than `defadvice`.
Fix some compilation warnings.
Prefer #' to quote function names.
Adjust `Package-Requires:` accordingly.
2026-01-17 12:33:34 -05:00
Renato Ferreira 2cd802b1f7 Use built-in line-number-at-pos in Emacs >= 28 (#373) 2026-01-08 22:09:20 +13:00
Pedro A. Aranda Gutiérrez 9017f3be6b Add lexical binding cookies (#389)
* Add lexical binding cookies

* multiple-cursors-core.el: Pacify lexical-binding frenzy in master

* multiple-cursors-core.el: when saving mc/list-file, prepend a
lexical binding flag to avoid emacs master from screaming.  When
inserting strings, use `\\n' instead of (newline).
2025-10-06 13:38:27 -07:00
Magnar Sveen 89f1a8df9b Release 1.5.0 2025-02-10 19:13:49 +01:00
Magnar Sveen 758223c45b Merge pull request #388 from emacsmirror/expkg
Move metadata from multiple-cursors-pkg.el to multiple-cursors.el
2025-02-10 19:12:54 +01:00
Jonas Bernoulli bb07ffee68 Move metadata from multiple-cursors-pkg.el to multiple-cursors.el 2024-12-26 17:55:18 +01:00
Magnar Sveen dd10cf2334 Merge pull request #387 from arialdomartini/tables
List of commands in a table
2024-12-02 17:31:03 +01:00
Arialdo Martini 3317246070 List of commands in a table, to improve readability 2024-12-02 15:55:39 +01:00
Magnar Sveen 46635e7f69 Merge pull request #386 from AjaiKN/symbol-value
Use symbol-value instead of eval
2024-12-01 19:41:18 +01:00
Ajai Nelson e315120117 Use symbol-value instead of eval
The Emacs Lisp manual says, "to get the value of a variable, while eval
works, symbol-value is preferable".
2024-11-27 08:40:16 -05:00
Leo Gaskin c870c18462 Merge pull request #383 from LaurenceWarne/fix-byte-comp-warnings
Fix byte compilation warnings
2024-02-23 12:34:45 +01:00
Laurence Warne ba7852f192 Move mc/mark-more-like-this-extended-keymap defvar location 2024-02-13 21:03:23 +00:00
Leo Gaskin d36c62aa71 Merge pull request #384 from cryptorick/fix-version
Align version numbers
2024-02-13 18:34:26 +01:00
cryptorick 5ab154b09e align version numbers 2024-02-12 23:45:40 -05:00
Laurence Warne 25b0dca82e Fix byte compilation warnings
Fix the byte compilation warnings:

In mc--read-char:
multiple-cursors-core.el:347:2: Warning: reference to free variable ‘multiple-cursors-mode’

In mc--read-quoted-char:
multiple-cursors-core.el:348:2: Warning: reference to free variable ‘multiple-cursors-mode’

In mc--register-read-with-preview:
multiple-cursors-core.el:349:2: Warning: reference to free variable ‘multiple-cursors-mode’

In mc--read-char-from-minibuffer:
multiple-cursors-core.el:350:2: Warning: reference to free variable ‘multiple-cursors-mode’

In toplevel form:
mc-mark-more.el:95:2: Warning: defvar `mc/enclose-search-term' docstring has wrong usage of unescaped single quotes (use \= or different quoting)

In mc/mark-more-like-this-extended:
mc-mark-more.el:501:2: Warning: docstring has wrong usage of unescaped single quotes (use \= or different quoting)
mc-mark-more.el:522:22: Warning: reference to free variable ‘mc/mark-more-like-this-extended-keymap’

In end of data:
mc-mark-more.el:724:27: Warning: the function ‘sgml-skip-tag-forward’ is not known to be defined.
mc-mark-more.el:673:8: Warning: the function ‘sgml-get-context’ is not known to be defined.

In end of data:
mc-hide-unmatched-lines-mode.el:110:1: Warning: the function ‘sgml-skip-tag-forward’ is not known to be defined.
mc-hide-unmatched-lines-mode.el:110:1: Warning: the function ‘sgml-get-context’ is not known to be defined.

In end of data:
multiple-cursors-core.el:567:43: Warning: the function ‘sgml-skip-tag-forward’ is not known to be defined.
multiple-cursors-core.el:535:25: Warning: the function ‘sgml-get-context’ is not known to be defined.

In end of data:
mc-cycle-cursors.el:124:1: Warning: the function ‘sgml-skip-tag-forward’ is not known to be defined.
mc-cycle-cursors.el:124:1: Warning: the function ‘sgml-get-context’ is not known to be defined.
2024-02-11 20:35:00 +00:00
Magnar Sveen 234806c832 Merge pull request #382 from ayyess/master
Support commands with multiple read-chars
2023-07-28 07:18:59 +02:00
Andrew Scott 25b98b940c Support commands with multiple read-chars
This change fixes commands that read-chars multiple times. Previously, two
stage commands like embrace-change would read the same char twice immediately
and avy-goto-char-timer would never stop reading input as a cached value was
always provided during the timer. Instead, the read-char prompt is included in
the cache key so that multiple different calls are cached separately and
accessible by the fake cursors.
2023-07-28 00:05:13 +01:00
Magnar Sveen 6956e8e12e Add autoload to activate-cursor-for-undo
This solves an issue where packages are loaded mid undo-session with undo-fu
2023-03-09 13:04:31 +01:00
Leo Gaskin 16223efc2d Fix byte compiler warnings by moving variable declarations 2023-01-13 09:35:03 +01:00
Leo Gaskin 7f255ce696 Remove notes saying that "M-x" isn't properly supported 2022-12-24 13:26:12 +01:00
Leo Gaskin 351eb6cbb5 Add multiple-cursors support to execute-extended-command
Also add three new tests for this functionality and adapt some existing
tests as well as the testing harness.
2022-12-24 13:26:12 +01:00
Leo Gaskin 558198239e Disable CI support for old versions of Emacs
Cask has seemingly stopped properly supporting these versions as
indicated by the commit cask/cask@685c4c1.
2022-12-23 16:22:43 +01:00
Leo Gaskin 817a7a8d25 Fix problem aborting mc/edit-lines when not in transient-mark-mode 2022-12-23 16:22:43 +01:00
Leo Gaskin c9ea562bd5 Fix regression with determining the current sgml context
This problem seems to have been introduced in commit aae47ae by adding
"100" as an argument to "looking-back" instead of the correct "1".
2022-12-23 16:22:43 +01:00
Leo Gaskin 72de6a4ec4 Use latest major version of actions/checkout for CI 2022-12-23 16:22:43 +01:00
Leo Gaskin 03bc44e093 Use new recommended Cask installation method 2022-12-23 16:22:43 +01:00
Troy Brown fe0d516745 Detect cursor bar type when specified by the frame.
When the 'cursor-type' for the buffer is specified by the frame, this
was not detected by the current logic as 'cursor-type' will be set to
't' and thus not explicitly match 'bar'.  This update checks to see if
'cursor-type' is specified by the frame and will pull the parameter
from the frame if it is, prior to subsequent checks.
2022-11-26 08:43:42 +01:00
Seungheon Oh 1e4842d129 Fix mc/mark-all-in-region leaving fake cursor.
Previously this function left a remain of fake function if there was
only one matching string in selected region.
2022-08-21 11:32:12 +02:00
Ryan Davis 225fc0e889 Extend advising functions for read-char and quoted-read-char w/ macro
Add register-read-with-preview and read-char-from-minibuffer to cover
insert-register and zap-to-char, respectively.

Also add mc--reset-read-variables to for mc--reset-read-prompts to use
dynamically so these can be further extended via the macro.
2022-06-13 23:22:50 +02:00
Will B Chang fd8441bfc8 support undo-fu commands
https://github.com/emacsmirror/undo-fu
2022-05-28 14:15:14 +02:00
Steve Purcell 2f003612b7 Use GitHub Actions in place of Travis, and test more Emacs versions (#365)
* Use GitHub Actions in place of Travis, and test more Emacs versions

* Run tests in Actions via `script` to fake a TTY

* Add newer emacs versions to CI matrix
2022-05-22 23:54:21 +12:00
Jason May aae47aebc0 eliminate byte-compilation warnings
- long docstrings
- "defcustom fails to specify type" - use '(sexp)
- keyword arguments in define-minor-mode
- deprecations
2022-03-28 19:24:00 +02:00
Johannes Lippmann 8a60fc7ef0 Document multiple-cursors-mode-disabled-hook in Readme 2021-11-12 23:23:42 +01:00
Johannes Lippmann b139bb6b30 introduce function mc/disable-multiple-cursors-mode 2021-11-12 23:23:42 +01:00
Johannes Lippmann 4975afedb3 Run hook when mc is disabled 2021-11-12 23:23:42 +01:00
Philip K 588daf8c52 Mention NonGNU ELPA
Hi,

multiple-cursors has recently been added to [NonGNU ELPA](https://elpa.nongnu.org/), allowing Emacs 28+ users to install it without any additional configuration.

This patch mentions NonGNU in the README, so that users know that it can be installed by default.

Otherwise, the only thing worth noting is that NonGNU ELPA distributes stable versions by default, and these are identified by commits that modify the version tag in the package header. I'm not sure if new versions are to be expected, but in case there is an update, please remember to update the version tag too.
2021-08-08 13:05:02 +02:00
Kaligule 616fbdd369 Document existing functions in Readme
mc/vertical-align
mc/vertical-align-with-space

I have wanted that functions for so long, only to find out now that they have existed for 7 years!
2021-04-21 11:11:19 +02:00
Amory Meltzer 7b13b03c99 Add homepage 2021-03-23 12:28:43 +01:00
Vedang Manerikar cb93501ec7 Minor backward compatibility fix to remove warning
This removes the deprecation warning around `return-from'
2021-03-22 19:44:31 +01:00
Zach Kost-Smith a9d7764f80 Add option to disable bar-style fake cursors (#367) 2020-12-15 07:59:00 -08:00
Jen-Chieh Shen 83abb0533a Add badges to README (#363)
* Add badges to README

* Update README.md

Co-authored-by: Steve Purcell <steve@sanityinc.com>

Co-authored-by: Steve Purcell <steve@sanityinc.com>
2020-10-25 13:27:10 +13:00
Masahiro Nakamura 7763f4f9d7 Load mc-cycle-cursors and mc-hide-unmatched-lines-mode after loading multiple-cursors-core
This is useful with autoloaded commands.
2020-10-18 07:38:52 +02:00
Masahiro Nakamura 6a04a147ce Fix docstrings
Fix wrong docstrings of mc/mark-next-word-like-this and
mc/mark-next-symbol-like-this.
2020-10-18 07:37:54 +02:00
Damien Cassou b880554d04 Fix typos (#359)
Typos found with codespell.
2019-12-10 09:59:45 -08:00
Magnar Sveen b9b851a767 Merge pull request #358 from renatofdds/master
Faster line-number-at-pos calculation
2019-08-20 09:49:53 +02:00
Renato Ferreira b39e9631d6 Faster line-number-at-pos calculation 2019-08-18 13:44:55 -03:00
Magnar Sveen 5ffb19af48 Update README.md 2019-03-21 06:57:00 +01:00
Magnar Sveen a730c414b1 Update README.md 2019-03-20 18:12:37 +01:00
Magnar Sveen fc6a6a7462 Merge pull request #355 from flatwhatson/lazy-list-file
Load mc/list-file as late as possible
2019-03-17 13:11:44 +01:00
Andrew Whatson d27870dff3 Load mc/list-file as late as possible
Previously the list file was loaded immediately upon loading
`multiple-cursors-core`.  This doesn't work well with modern autoloading
emacs configurations, where customisation is mostly done in
`eval-after-load` hooks; the default file location is loaded, *then*
the value of `mc/list-file` is changed, and everyone is confused.
2019-03-13 13:40:58 +10:00
Magnar Sveen 5ff2071fac Merge pull request #351 from jrosdahl/dabbrev-expand
Add dabbrev state variables to mc/cursor-specific-vars
2019-02-24 13:46:09 +01:00
Joel Rosdahl 9980faa21f Add dabbrev state variables to mc/cursor-specific-vars
Fixes #142.
2019-02-24 13:28:36 +01:00
19 changed files with 752 additions and 545 deletions
+36
View File
@@ -0,0 +1,36 @@
name: CI
on:
pull_request:
push:
paths-ignore:
- '**.md'
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
emacs_version:
- 25.1
- 25.2
- 25.3
- 26.1
- 26.2
- 26.3
- 27.2
- 28.1
- snapshot
steps:
- uses: purcell/setup-emacs@master
with:
version: ${{ matrix.emacs_version }}
- name: Install Cask
run: git clone https://github.com/cask/cask ~/.cask
- name: Add Cask to PATH
run: echo "$HOME/.cask/bin" >> $GITHUB_PATH
- uses: actions/checkout@v3
- name: Install dependencies with Cask
run: cask
- name: Run tests
run: script -e -c /bin/bash -c 'TERM=xterm ./run-tests.sh'
+4
View File
@@ -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
View File
@@ -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
+76 -43
View File
@@ -1,14 +1,38 @@
# multiple-cursors.el [![Build Status](https://secure.travis-ci.org/magnars/multiple-cursors.el.png)](http://travis-ci.org/magnars/multiple-cursors.el) [![Build Status](https://github.com/magnars/multiple-cursors.el/workflows/CI/badge.svg)](https://github.com/magnars/multiple-cursors.el/actions)
[![MELPA](https://melpa.org/packages/multiple-cursors-badge.svg)](https://melpa.org/#/multiple-cursors)
[![MELPA Stable](https://stable.melpa.org/packages/multiple-cursors-badge.svg)](https://stable.melpa.org/#/multiple-cursors)
[![NonGNU ELPA](https://elpa.nongnu.org/nongnu/multiple-cursors.svg)](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.
+29
View File
@@ -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"
+2
View File
@@ -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))
"-")))) "-"))))
+10 -6
View File
@@ -1,8 +1,10 @@
(let* ((current-directory (file-name-directory load-file-name)) ;; -*- lexical-binding: t; -*-
(features-directory (expand-file-name ".." current-directory)) (defvar multiple-cursors-root-path
(project-directory (expand-file-name ".." features-directory))) (let* ((current-directory (file-name-directory load-file-name))
(setq multiple-cursors-root-path project-directory) (features-directory (expand-file-name ".." current-directory)))
(setq multiple-cursors-util-path (expand-file-name "util" project-directory))) (expand-file-name ".." features-directory)))
(defvar multiple-cursors-util-path
(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
View File
@@ -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
View File
@@ -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)
+11 -9
View File
@@ -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)
+82 -51
View File
@@ -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)
@@ -55,7 +56,7 @@
beg)) beg))
(defun mc/furthest-cursor-before-point () (defun mc/furthest-cursor-before-point ()
(let ((beg (if mark-active (min (mark) (point)) (point))) (let ((beg (or (use-region-beginning) (point)))
furthest) furthest)
(mc/for-each-fake-cursor (mc/for-each-fake-cursor
(when (< (mc/cursor-beg cursor) beg) (when (< (mc/cursor-beg cursor) beg)
@@ -64,7 +65,7 @@
furthest)) furthest))
(defun mc/furthest-cursor-after-point () (defun mc/furthest-cursor-after-point ()
(let ((end (if mark-active (max (mark) (point)) (point))) (let ((end (or (use-region-end) (point)))
furthest) furthest)
(mc/for-each-fake-cursor (mc/for-each-fake-cursor
(when (> (mc/cursor-end cursor) end) (when (> (mc/cursor-end cursor) end)
@@ -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
View File
@@ -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)
+5 -4
View File
@@ -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)))
+422 -328
View File
@@ -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."
(load mc/list-file 'noerror 'nomessage) (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)
(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
-3
View File
@@ -1,3 +0,0 @@
(define-package "multiple-cursors" "1.3.0"
"Multiple cursors for Emacs."
'((cl-lib "0.5")))
+7 -8
View File
@@ -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
View File
@@ -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)
-13
View File
@@ -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