mirror of
https://github.com/magnars/multiple-cursors.el.git
synced 2026-05-10 09:28:18 +00:00
Compare commits
2 Commits
1.5.0
..
cl-tidy-up
| Author | SHA1 | Date | |
|---|---|---|---|
| 48e1d3da5c | |||
| 1f3ccfbcd2 |
@@ -1,36 +0,0 @@
|
||||
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'
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
language: emacs-lisp
|
||||
before_install:
|
||||
- if [ "$EMACS" = 'emacs-snapshot' ]; then
|
||||
sudo add-apt-repository -y ppa:cassou/emacs &&
|
||||
sudo apt-get update -qq &&
|
||||
sudo apt-get install -qq
|
||||
emacs-snapshot-el emacs-snapshot-gtk emacs-snapshot;
|
||||
fi
|
||||
- if [ "$EMACS" = 'emacs24' ]; then
|
||||
sudo add-apt-repository -y ppa:cassou/emacs &&
|
||||
sudo apt-get update -qq &&
|
||||
sudo apt-get install -qq
|
||||
emacs24 emacs24-el emacs24-common-non-dfsg;
|
||||
fi
|
||||
- curl -fsSkL https://raw.github.com/cask/cask/master/go | python
|
||||
- export PATH="/home/travis/.cask/bin:$PATH"
|
||||
- cask
|
||||
env:
|
||||
- EMACS=emacs24 TAGS=""
|
||||
script:
|
||||
./run-travis-ci.sh
|
||||
@@ -1,9 +1,4 @@
|
||||
[](https://github.com/magnars/multiple-cursors.el/actions)
|
||||
[](https://melpa.org/#/multiple-cursors)
|
||||
[](https://stable.melpa.org/#/multiple-cursors)
|
||||
[](https://elpa.nongnu.org/nongnu/multiple-cursors.html)
|
||||
|
||||
# multiple-cursors.el
|
||||
# multiple-cursors.el [](http://travis-ci.org/magnars/multiple-cursors.el)
|
||||
|
||||
Multiple cursors for Emacs. This is some pretty crazy functionality, so yes,
|
||||
there are kinks. Don't be afraid though, I've been using it since 2011 with
|
||||
@@ -30,9 +25,7 @@ TLDR: *I am still maintaining this package*, but I am no longer crowdsourcing a
|
||||
|
||||
I highly recommend installing multiple-cursors through `package.el`.
|
||||
|
||||
It's available on [MELPA](http://melpa.org/), [MELPA Stable](http://stable.melpa.org) and
|
||||
[NonGNU ELPA](https://elpa.nongnu.org/nongnu/multiple-cursors.html) (enabled by default
|
||||
from Emacs 28 onwards):
|
||||
It's available on [MELPA](http://melpa.org/) and [MELPA Stable](http://stable.melpa.org):
|
||||
|
||||
M-x package-install multiple-cursors
|
||||
|
||||
@@ -67,6 +60,10 @@ To get out of multiple-cursors-mode, press `<return>` or `C-g`. The latter will
|
||||
first disable multiple regions before disabling multiple cursors. If you want to
|
||||
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
|
||||
|
||||
You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.com/e13.html).
|
||||
@@ -75,59 +72,49 @@ You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.co
|
||||
|
||||
### Mark one more occurrence
|
||||
|
||||
| Command | Description |
|
||||
|-------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `mc/mark-next-like-this` | Adds a cursor and region at the next part of the buffer forwards that matches the current region. |
|
||||
| `mc/mark-next-like-this-word` | Adds a cursor and region at the next part of the buffer forwards that matches the current region, if no region is selected it selects the word at the point. |
|
||||
| `mc/mark-next-like-this-symbol` | Adds a cursor and region at the next part of the buffer forwards that matches the current region, if no region is selected it selects the symbol at the point. |
|
||||
| `mc/mark-next-word-like-this` | Like `mc/mark-next-like-this` but only for whole words. |
|
||||
| `mc/mark-next-symbol-like-this` | Like `mc/mark-next-like-this` but only for whole symbols. |
|
||||
| `mc/mark-previous-like-this` | Adds a cursor and region at the next part of the buffer backwards that matches the current region. |
|
||||
| `mc/mark-previous-like-this-word` | Adds a cursor and region at the next part of the buffer backwards that matches the current region, if no region is selected it selects the word at the point. |
|
||||
| `mc/mark-previous-like-this-symbol` | Adds a cursor and region at the next part of the buffer backwards that matches the current region, if no region is selected it selects the symbol at the point. |
|
||||
| `mc/mark-previous-word-like-this` | Like `mc/mark-previous-like-this` but only for whole words. |
|
||||
| `mc/mark-previous-symbol-like-this` | Like `mc/mark-previous-like-this` but only for whole symbols. |
|
||||
| `mc/mark-more-like-this-extended` | Use arrow keys to quickly mark/skip next/previous occurrences. |
|
||||
| `mc/add-cursor-on-click` | Bind to a mouse event to add cursors by clicking. See tips-section. |
|
||||
| `mc/mark-pop` | Set a cursor at the current point and move to the next (different) position on the mark stack. This allows for fine grained control over the placement of cursors. |
|
||||
- `mc/mark-next-like-this`: Adds a cursor and region at the next part of the buffer forwards that matches the current region.
|
||||
- `mc/mark-next-like-this-word`: Adds a cursor and region at the next part of the buffer forwards that matches the current region, if no region is selected it selects the word at the point.
|
||||
- `mc/mark-next-like-this-symbol`: Adds a cursor and region at the next part of the buffer forwards that matches the current region, if no region is selected it selects the symbol at the point.
|
||||
- `mc/mark-next-word-like-this`: Like `mc/mark-next-like-this` but only for whole words.
|
||||
- `mc/mark-next-symbol-like-this`: Like `mc/mark-next-like-this` but only for whole symbols.
|
||||
- `mc/mark-previous-like-this`: Adds a cursor and region at the next part of the buffer backwards that matches the current region.
|
||||
- `mc/mark-previous-like-this-word`: Adds a cursor and region at the next part of the buffer backwards that matches the current region, if no region is selected it selects the word at the point.
|
||||
- `mc/mark-previous-like-this-symbol`: Adds a cursor and region at the next part of the buffer backwards that matches the current region, if no region is selected it selects the symbol at the point.
|
||||
- `mc/mark-previous-word-like-this`: Like `mc/mark-previous-like-this` but only for whole words.
|
||||
- `mc/mark-previous-symbol-like-this`: Like `mc/mark-previous-like-this` but only for whole symbols.
|
||||
- `mc/mark-more-like-this-extended`: Use arrow keys to quickly mark/skip next/previous occurrences.
|
||||
- `mc/add-cursor-on-click`: Bind to a mouse event to add cursors by clicking. See tips-section.
|
||||
- `mc/mark-pop`: Set a cursor at the current point and move to the next (different) position on the mark stack. This allows for fine grained control over the placement of cursors.
|
||||
|
||||
### Juggle around with the current cursors
|
||||
|
||||
| Command | Description |
|
||||
|---------------------------------|--------------------------------------------------------------------|
|
||||
| `mc/unmark-next-like-this` | Remove the cursor furthest down in the buffer. |
|
||||
| `mc/unmark-previous-like-this` | Remove the cursor furthest up in the buffer. |
|
||||
| `mc/skip-to-next-like-this` | Remove the cursor furthest down, marking the next occurrence down. |
|
||||
| `mc/skip-to-previous-like-this` | Remove the cursor furthest up, marking the next occurrence up. |
|
||||
- `mc/unmark-next-like-this`: Remove the cursor furthest down in the buffer.
|
||||
- `mc/unmark-previous-like-this`: Remove the cursor furthest up in the buffer.
|
||||
- `mc/skip-to-next-like-this`: Remove the cursor furthest down, marking the next occurrence down.
|
||||
- `mc/skip-to-previous-like-this`: Remove the cursor furthest up, marking the next occurrence up.
|
||||
|
||||
### Mark many occurrences
|
||||
|
||||
| Command | Description |
|
||||
|------------------------------------------|-------------------------------------------------------------------------------------|
|
||||
| `mc/edit-lines` | Adds one cursor to each line in the current region. |
|
||||
| `mc/edit-beginnings-of-lines` | Adds a cursor at the start of each line in the current region. |
|
||||
| `mc/edit-ends-of-lines` | Adds a cursor at the end of each line in the current region. |
|
||||
| `mc/mark-all-like-this` | Marks all parts of the buffer that matches the current region. |
|
||||
| `mc/mark-all-words-like-this` | Like `mc/mark-all-like-this` but only for whole words. |
|
||||
| `mc/mark-all-symbols-like-this` | Like `mc/mark-all-like-this` but only for whole symbols. |
|
||||
| `mc/mark-all-in-region` | Prompts for a string to match in the region, adding cursors to all of them. |
|
||||
| `mc/mark-all-like-this-in-defun` | Marks all parts of the current defun that matches the current region. |
|
||||
| `mc/mark-all-words-like-this-in-defun` | Like `mc/mark-all-like-this-in-defun` but only for whole words. |
|
||||
| `mc/mark-all-symbols-like-this-in-defun` | Like `mc/mark-all-like-this-in-defun` but only for whole symbols. |
|
||||
| `mc/mark-all-dwim` | Tries to be smart about marking everything you want. Can be pressed multiple times. |
|
||||
- `mc/edit-lines`: Adds one cursor to each line in the current region.
|
||||
- `mc/edit-beginnings-of-lines`: Adds a cursor at the start of each line in the current region.
|
||||
- `mc/edit-ends-of-lines`: Adds a cursor at the end of each line in the current region.
|
||||
- `mc/mark-all-like-this`: Marks all parts of the buffer that matches the current region.
|
||||
- `mc/mark-all-words-like-this`: Like `mc/mark-all-like-this` but only for whole words.
|
||||
- `mc/mark-all-symbols-like-this`: Like `mc/mark-all-like-this` but only for whole symbols.
|
||||
- `mc/mark-all-in-region`: Prompts for a string to match in the region, adding cursors to all of them.
|
||||
- `mc/mark-all-like-this-in-defun`: Marks all parts of the current defun that matches the current region.
|
||||
- `mc/mark-all-words-like-this-in-defun`: Like `mc/mark-all-like-this-in-defun` but only for whole words.
|
||||
- `mc/mark-all-symbols-like-this-in-defun`: Like `mc/mark-all-like-this-in-defun` but only for whole symbols.
|
||||
- `mc/mark-all-dwim`: Tries to be smart about marking everything you want. Can be pressed multiple times.
|
||||
|
||||
### Special
|
||||
|
||||
| Command | Description |
|
||||
|---------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `set-rectangular-region-anchor` | Think of this one as `set-mark` except you're marking a rectangular region. |
|
||||
| `mc/mark-sgml-tag-pair` | Mark the current opening and closing tag. |
|
||||
| `mc/insert-numbers` | Insert increasing numbers for each cursor, top to bottom. |
|
||||
| `mc/insert-letters` | Insert increasing letters for each cursor, top to bottom. |
|
||||
| `mc/sort-regions` | Sort the marked regions alphabetically. |
|
||||
| `mc/reverse-regions` | Reverse the order of the marked regions. |
|
||||
| `mc/vertical-align` | Aligns all cursors vertically with a given CHARACTER to the one with the highest column number (the rightest). (Might not behave as intended if more than one cursors are on the same line.) |
|
||||
| `mc/vertical-align-with-space` | Aligns all cursors with whitespace like `mc/vertical-align` does. |
|
||||
- `set-rectangular-region-anchor`: Think of this one as `set-mark` except you're marking a rectangular region.
|
||||
- `mc/mark-sgml-tag-pair`: Mark the current opening and closing tag.
|
||||
- `mc/insert-numbers`: Insert increasing numbers for each cursor, top to bottom.
|
||||
- `mc/insert-letters`: Insert increasing letters for each cursor, top to bottom.
|
||||
- `mc/sort-regions`: Sort the marked regions alphabetically.
|
||||
- `mc/reverse-regions`: Reverse the order of the marked regions.
|
||||
|
||||
## Tips and tricks
|
||||
|
||||
@@ -166,10 +153,6 @@ 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
|
||||
when the region is active, you can try [region-bindings-mode](https://github.com/fgallina/region-bindings-mode).
|
||||
|
||||
- There is a special hook that is run when the mode is diabled
|
||||
(which is equivalent to the number of cursors going back to 1):
|
||||
`multiple-cursors-mode-disabled-hook`
|
||||
|
||||
BTW, I highly recommend adding `mc/mark-next-like-this` to a key binding that's
|
||||
right next to the key for `er/expand-region`.
|
||||
|
||||
@@ -208,6 +191,7 @@ run once to `mc/cmds-to-run-once` in ".mc-lists.el".
|
||||
|
||||
* 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).
|
||||
* Commands run with `M-x` won't be repeated for all cursors.
|
||||
* All key bindings that refer to lambdas are always run for all cursors. If you
|
||||
need to limit it, you will have to give it a name.
|
||||
* Redo might screw with your cursors. Undo works very well.
|
||||
|
||||
@@ -50,13 +50,6 @@ Feature: Multiple cursors core
|
||||
And I press "C-!"
|
||||
Then I should see "This aatext contains the word aatext twice"
|
||||
|
||||
Scenario: Unknown command with multiple read: yes, do for all
|
||||
Given I have bound C-! to a new command that inserts two read-chars
|
||||
And I have cursors at "text" in "This text contains the word text twice"
|
||||
When I press "C-! b c y"
|
||||
And I press "C-! d e"
|
||||
Then I should see "This bcdetext contains the word bcdetext twice"
|
||||
|
||||
Scenario: Unknown command: no, don't do for all
|
||||
Given I have bound C-! to another new command that inserts "a"
|
||||
And I have cursors at "text" in "This text contains the word text twice"
|
||||
@@ -64,28 +57,6 @@ Scenario: Unknown command with multiple read: yes, do for all
|
||||
And I press "C-!"
|
||||
Then I should see "This aatext contains the word text twice"
|
||||
|
||||
Scenario: Multiple supported M-x command (forward-word in this case)
|
||||
Given I have cursors at "text" in "This text contains the word text twice"
|
||||
And I type "("
|
||||
And I press "M-x forward-word"
|
||||
And I press "M-x forward-word"
|
||||
And I type ")"
|
||||
Then I should see "This (text contains) the word (text twice)"
|
||||
|
||||
Scenario: Unknown M-x command: yes, do for all
|
||||
Given I have cursors at "text" in "This text contains the word text twice"
|
||||
And I press "C-SPC"
|
||||
And I press "M-f"
|
||||
And I press "M-x upcase-dwim RET y"
|
||||
Then I should see "This TEXT contains the word TEXT twice"
|
||||
|
||||
Scenario: Unknown M-x command: no, don't do for all
|
||||
Given I have cursors at "text" in "This text contains the word text twice"
|
||||
And I press "C-SPC"
|
||||
And I press "M-f"
|
||||
And I press "M-x upcase-dwim RET n"
|
||||
Then I should see "This TEXT contains the word text twice"
|
||||
|
||||
Scenario: Undo
|
||||
Given I have cursors at "text" in "This text contains the word text twice"
|
||||
When I press "M-f"
|
||||
|
||||
@@ -8,7 +8,6 @@ Feature: Repeat last interactive command for fake cursors (mc/repeat-command)
|
||||
And I press "RET"
|
||||
And I type "21"
|
||||
And I press "RET"
|
||||
And I type "n"
|
||||
And I press "C-:"
|
||||
And I press "y"
|
||||
And I execute the action chain
|
||||
@@ -28,7 +27,6 @@ Feature: Repeat last interactive command for fake cursors (mc/repeat-command)
|
||||
Scenario: Disable prompt
|
||||
Given I have cursors at "text" in "This text/0000 contains the word text/1111 thrice (text/2222)"
|
||||
When I set mc/always-repeat-command to t
|
||||
When I set mc/always-run-for-all to t
|
||||
When I start an action chain
|
||||
And I press "M-x"
|
||||
And I type "zap-to-char"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(require 'cl) ;; For lexical-let
|
||||
;; -*- lexical-binding: t -*-
|
||||
|
||||
(When "^I mark next like this$"
|
||||
(lambda () (call-interactively 'mc/mark-next-like-this)))
|
||||
@@ -109,31 +109,22 @@
|
||||
|
||||
(When "^I copy \"\\(.+\\)\" in another program$"
|
||||
(lambda (text)
|
||||
(lexical-let ((text text))
|
||||
(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 \"\\(.+\\)\"$"
|
||||
(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 \"\\(.+\\)\"$"
|
||||
(lambda (ins)
|
||||
(lexical-let ((ins 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 \"\\(.+\\)\"$"
|
||||
(lambda (ins)
|
||||
(lexical-let ((ins ins))
|
||||
(defun mc-test-temp-command-2 () (interactive) (insert ins))
|
||||
(global-set-key (kbd "C-!") 'mc-test-temp-command-2))))
|
||||
|
||||
(Given "^I have bound C-! to a new command that inserts two read-chars$"
|
||||
(lambda ()
|
||||
(defun mc-test-temp-command-3 () (interactive) (insert (read-char "first: ")) (insert (read-char "second: ")))
|
||||
(global-set-key (kbd "C-!") 'mc-test-temp-command-3)))
|
||||
(global-set-key (kbd "C-!") 'mc-test-temp-command-2)))
|
||||
|
||||
(Given "^I have bound C-! to a keyboard macro that insert \"_\"$"
|
||||
(lambda ()
|
||||
|
||||
@@ -45,8 +45,6 @@
|
||||
(subword-mode 0)
|
||||
(wrap-region-mode 0)
|
||||
(setq set-mark-default-inactive nil)
|
||||
(deactivate-mark)
|
||||
(setq mc/cmds-to-run-for-all nil)
|
||||
(setq mc/cmds-to-run-once nil))
|
||||
(deactivate-mark))
|
||||
|
||||
(After)
|
||||
|
||||
@@ -88,11 +88,7 @@
|
||||
(cl-defun mc/cycle (next-cursor fallback-cursor loop-message)
|
||||
(when (null next-cursor)
|
||||
(when (eql 'stop (mc/handle-loop-condition loop-message))
|
||||
(cond
|
||||
((fboundp 'cl-return-from)
|
||||
(cl-return-from mc/cycle nil))
|
||||
((fboundp 'return-from)
|
||||
(cl-return-from mc/cycle nil))))
|
||||
(setf next-cursor fallback-cursor))
|
||||
(mc/create-fake-cursor-at-point)
|
||||
(mc/pop-state-from-overlay next-cursor)
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ that symbol is used instead of `mc/edit-lines-empty-lines'.
|
||||
Otherwise, if ARG negative, short lines will be ignored. Any
|
||||
other non-nil value will cause short lines to be padded."
|
||||
(interactive "P")
|
||||
(unless mark-active
|
||||
(when (not (and mark-active (/= (point) (mark))))
|
||||
(error "Mark a set of lines first"))
|
||||
(mc/remove-fake-cursors)
|
||||
(let* ((col (current-column))
|
||||
|
||||
@@ -54,9 +54,8 @@ also hum/lines-to-expand below and above) To make use of this
|
||||
mode press \"C-'\" while multiple-cursor-mode is active. You can
|
||||
still edit lines while you are in mc-hide-unmatched-lines
|
||||
mode. To leave this mode press <return> or \"C-g\""
|
||||
:init-value nil
|
||||
:lighter " hu"
|
||||
:keymap hum/hide-unmatched-lines-mode-map
|
||||
nil " hu"
|
||||
hum/hide-unmatched-lines-mode-map
|
||||
(if mc-hide-unmatched-lines-mode
|
||||
;;just in case if mc mode will be disabled while hide-unmatched-lines is active
|
||||
(progn
|
||||
|
||||
+42
-73
@@ -29,7 +29,6 @@
|
||||
|
||||
(require 'multiple-cursors-core)
|
||||
(require 'thingatpt)
|
||||
(require 'sgml-mode)
|
||||
|
||||
(defun mc/cursor-end (cursor)
|
||||
(if (overlay-get cursor 'mark-active)
|
||||
@@ -97,8 +96,8 @@ to (point)), or nil."
|
||||
"How should mc/mark-more-* search for more matches?
|
||||
|
||||
Match everything: nil
|
||||
Match only whole words: \\='words
|
||||
Match only whole symbols: \\='symbols
|
||||
Match only whole words: 'words
|
||||
Match only whole symbols: 'symbols
|
||||
|
||||
Use like case-fold-search, don't recommend setting it globally.")
|
||||
|
||||
@@ -211,13 +210,9 @@ With zero ARG, skip the last one and mark next."
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-previous-like-this (arg)
|
||||
"Find and mark the previous part of the buffer matching the
|
||||
currently active region.
|
||||
|
||||
If no region is active ,add a cursor on the previous line.
|
||||
|
||||
"Find and mark the previous part of the buffer matching the currently active region
|
||||
If no region is active add a cursor on the previous line
|
||||
With negative ARG, delete the last one instead.
|
||||
|
||||
With zero ARG, skip the last one and mark next."
|
||||
(interactive "p")
|
||||
(if (< arg 0)
|
||||
@@ -232,14 +227,9 @@ With zero ARG, skip the last one and mark next."
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-previous-like-this-word (arg)
|
||||
"Find and mark the previous part of the buffer matching the
|
||||
currently active region.
|
||||
|
||||
If no region is active, mark the word at the point and find the
|
||||
previous match.
|
||||
|
||||
"Find and mark the previous part of the buffer matching the currently active region
|
||||
If no region is active, mark the word at the point and find the previous match
|
||||
With negative ARG, delete the last one instead.
|
||||
|
||||
With zero ARG, skip the last one and mark previous."
|
||||
(interactive "p")
|
||||
(if (< arg 0)
|
||||
@@ -254,14 +244,9 @@ With zero ARG, skip the last one and mark previous."
|
||||
(mc/maybe-multiple-cursors-mode))
|
||||
|
||||
(defun mc/mark-previous-like-this-symbol (arg)
|
||||
"Find and mark the previous part of the buffer matching the
|
||||
currently active region.
|
||||
|
||||
If no region is active, mark the symbol at the point and find the
|
||||
previous match.
|
||||
|
||||
"Find and mark the previous part of the buffer matching the currently active region
|
||||
If no region is active, mark the symbol at the point and find the previous match
|
||||
With negative ARG, delete the last one instead.
|
||||
|
||||
With zero ARG, skip the last one and mark previous."
|
||||
(interactive "p")
|
||||
(if (< arg 0)
|
||||
@@ -278,15 +263,10 @@ With zero ARG, skip the last one and mark previous."
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-previous-word-like-this (arg)
|
||||
"Find and mark the previous part of the buffer matching the
|
||||
currently active region.
|
||||
|
||||
The matching region must be a whole word to be a match.
|
||||
|
||||
If no region is active, add a cursor on the previous line.
|
||||
|
||||
"Find and mark the previous part of the buffer matching the currently active region
|
||||
The matching region must be a whole word to be a match
|
||||
If no region is active add a cursor on the previous line
|
||||
With negative ARG, delete the last one instead.
|
||||
|
||||
With zero ARG, skip the last one and mark next."
|
||||
(interactive "p")
|
||||
(let ((mc/enclose-search-term 'words))
|
||||
@@ -294,15 +274,10 @@ With zero ARG, skip the last one and mark next."
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-previous-symbol-like-this (arg)
|
||||
"Find and mark the previous part of the buffer matching
|
||||
the currently active region.
|
||||
|
||||
The matching region must be a whole symbol to be a match.
|
||||
|
||||
If no region is active add a cursor on the previous line.
|
||||
|
||||
"Find and mark the previous part of the buffer matching the currently active region
|
||||
The matching region must be a whole symbol to be a match
|
||||
If no region is active add a cursor on the previous line
|
||||
With negative ARG, delete the last one instead.
|
||||
|
||||
With zero ARG, skip the last one and mark next."
|
||||
(interactive "p")
|
||||
(let ((mc/enclose-search-term 'symbols))
|
||||
@@ -349,15 +324,13 @@ With zero ARG, skip the last one and mark next."
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/skip-to-next-like-this ()
|
||||
"Skip the current one and select the next part of the buffer
|
||||
matching the currently active region."
|
||||
"Skip the current one and select the next part of the buffer matching the currently active region."
|
||||
(interactive)
|
||||
(mc/mark-next-like-this 0))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/skip-to-previous-like-this ()
|
||||
"Skip the current one and select the prev part of the buffer
|
||||
matching the currently active region."
|
||||
"Skip the current one and select the prev part of the buffer matching the currently active region."
|
||||
(interactive)
|
||||
(mc/mark-previous-like-this 0))
|
||||
|
||||
@@ -382,7 +355,7 @@ matching the currently active region."
|
||||
(when point-first (exchange-point-and-mark)))))
|
||||
(if (> (mc/num-cursors) 1)
|
||||
(multiple-cursors-mode 1)
|
||||
(mc/disable-multiple-cursors-mode)))
|
||||
(multiple-cursors-mode 0)))
|
||||
|
||||
(defun mc--select-thing-at-point (thing)
|
||||
(let ((bound (bounds-of-thing-at-point thing)))
|
||||
@@ -420,18 +393,16 @@ matching the currently active region."
|
||||
(progn
|
||||
(mc/remove-fake-cursors)
|
||||
(goto-char beg)
|
||||
(let ((lastmatch))
|
||||
(while (search-forward search end t)
|
||||
(push-mark (match-beginning 0))
|
||||
(mc/create-fake-cursor-at-point)
|
||||
(setq lastmatch t))
|
||||
(unless lastmatch
|
||||
(error "Search failed for %S" search)))
|
||||
(goto-char (match-end 0))
|
||||
(if (< (mc/num-cursors) 3)
|
||||
(mc/disable-multiple-cursors-mode)
|
||||
(mc/pop-state-from-overlay (mc/furthest-cursor-before-point))
|
||||
(multiple-cursors-mode 1))))))
|
||||
(mc/create-fake-cursor-at-point))
|
||||
(let ((first (mc/furthest-cursor-before-point)))
|
||||
(if (not first)
|
||||
(error "Search failed for %S" search)
|
||||
(mc/pop-state-from-overlay first)))
|
||||
(if (> (mc/num-cursors) 1)
|
||||
(multiple-cursors-mode 1)
|
||||
(multiple-cursors-mode 0))))))
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-all-in-region-regexp (beg end)
|
||||
@@ -456,7 +427,7 @@ matching the currently active region."
|
||||
(error "Search failed for %S" search)))
|
||||
(goto-char (match-end 0))
|
||||
(if (< (mc/num-cursors) 3)
|
||||
(mc/disable-multiple-cursors-mode)
|
||||
(multiple-cursors-mode 0)
|
||||
(mc/pop-state-from-overlay (mc/furthest-cursor-before-point))
|
||||
(multiple-cursors-mode 1))))))
|
||||
|
||||
@@ -498,40 +469,31 @@ remove the keymap depends on user input and KEEP-PRED:
|
||||
|
||||
(push alist emulation-mode-map-alists))))
|
||||
|
||||
(defvar mc/mark-more-like-this-extended-keymap (make-sparse-keymap))
|
||||
|
||||
(define-key mc/mark-more-like-this-extended-keymap (kbd "<up>") 'mc/mmlte--up)
|
||||
(define-key mc/mark-more-like-this-extended-keymap (kbd "<down>") 'mc/mmlte--down)
|
||||
(define-key mc/mark-more-like-this-extended-keymap (kbd "<left>") 'mc/mmlte--left)
|
||||
(define-key mc/mark-more-like-this-extended-keymap (kbd "<right>") 'mc/mmlte--right)
|
||||
|
||||
;;;###autoload
|
||||
(defun mc/mark-more-like-this-extended ()
|
||||
"Like mark-more-like-this, but then lets you adjust with arrow keys.
|
||||
"Like mark-more-like-this, but then lets you adjust with arrows key.
|
||||
The adjustments work like this:
|
||||
|
||||
<up> Mark previous like this and set direction to \\='up
|
||||
<down> Mark next like this and set direction to \\='down
|
||||
<up> Mark previous like this and set direction to 'up
|
||||
<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
|
||||
<right> Remove the cursor furthest up
|
||||
|
||||
If direction is \\='down:
|
||||
If direction is 'down:
|
||||
|
||||
<left> Remove the cursor furthest down
|
||||
<right> Skip past the cursor furthest down
|
||||
|
||||
The bindings for these commands can be changed.
|
||||
See `mc/mark-more-like-this-extended-keymap'."
|
||||
The bindings for these commands can be changed. See `mc/mark-more-like-this-extended-keymap'."
|
||||
(interactive)
|
||||
(mc/mmlte--down)
|
||||
(set-transient-map mc/mark-more-like-this-extended-keymap t))
|
||||
(set-temporary-overlay-map mc/mark-more-like-this-extended-keymap t))
|
||||
|
||||
(defvar mc/mark-more-like-this-extended-direction nil
|
||||
"When using mc/mark-more-like-this-extended
|
||||
are we working on the next or previous cursors?")
|
||||
"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)
|
||||
|
||||
@@ -566,6 +528,13 @@ are we working on the next or previous cursors?")
|
||||
(mc/skip-to-next-like-this))
|
||||
(mc/mmlte--message))
|
||||
|
||||
(defvar mc/mark-more-like-this-extended-keymap (make-sparse-keymap))
|
||||
|
||||
(define-key mc/mark-more-like-this-extended-keymap (kbd "<up>") 'mc/mmlte--up)
|
||||
(define-key mc/mark-more-like-this-extended-keymap (kbd "<down>") 'mc/mmlte--down)
|
||||
(define-key mc/mark-more-like-this-extended-keymap (kbd "<left>") 'mc/mmlte--left)
|
||||
(define-key mc/mark-more-like-this-extended-keymap (kbd "<right>") 'mc/mmlte--right)
|
||||
|
||||
(defvar mc--restrict-mark-all-to-symbols nil)
|
||||
|
||||
;;;###autoload
|
||||
@@ -670,7 +639,7 @@ If the region is inactive or on a single line, it will behave like
|
||||
(last
|
||||
(progn
|
||||
(when (looking-at "<") (forward-char 1))
|
||||
(when (looking-back ">" 1) (forward-char -1))
|
||||
(when (looking-back ">") (forward-char -1))
|
||||
(sgml-get-context)))))
|
||||
|
||||
(defun mc--on-tag-name-p ()
|
||||
|
||||
@@ -106,8 +106,7 @@
|
||||
(progn
|
||||
(mc/mark-next-lines 1)
|
||||
(mc/reverse-regions)
|
||||
(mc/disable-multiple-cursors-mode)
|
||||
)
|
||||
(multiple-cursors-mode 0))
|
||||
(unless (use-region-p)
|
||||
(mc/execute-command-for-all-cursors 'mark-sexp))
|
||||
(setq mc--strings-to-replace (nreverse (mc--ordered-region-strings)))
|
||||
|
||||
+334
-385
@@ -28,6 +28,8 @@
|
||||
(require 'cl-lib)
|
||||
(require 'rect)
|
||||
|
||||
(defvar mc--read-char)
|
||||
|
||||
(defface mc/cursor-face
|
||||
'((t (:inverse-video t)))
|
||||
"The face used for fake cursors"
|
||||
@@ -38,18 +40,6 @@
|
||||
"The face used for fake cursors if the cursor-type is bar"
|
||||
: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
|
||||
'((t :inherit region))
|
||||
"The face used for fake regions"
|
||||
@@ -115,13 +105,9 @@ rendered or shift text."
|
||||
|
||||
(defun mc/cursor-is-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)
|
||||
(and (listp cursor-type)
|
||||
(eq (car cursor-type) 'bar)))))
|
||||
(eq (car cursor-type) 'bar))))
|
||||
|
||||
(defun mc/line-number-at-pos (&optional pos absolute)
|
||||
"Faster implementation of `line-number-at-pos'."
|
||||
@@ -139,7 +125,7 @@ rendered or shift text."
|
||||
(defun mc/make-cursor-overlay-at-eol (pos)
|
||||
"Create overlay to look like cursor at end of line."
|
||||
(let ((overlay (make-overlay pos pos nil nil nil)))
|
||||
(if (and mc/match-cursor-style (mc/cursor-is-bar))
|
||||
(if (mc/cursor-is-bar)
|
||||
(overlay-put overlay 'before-string (propertize "|" 'face 'mc/cursor-bar-face))
|
||||
(overlay-put overlay 'after-string (propertize " " 'face 'mc/cursor-face)))
|
||||
overlay))
|
||||
@@ -147,7 +133,7 @@ rendered or shift text."
|
||||
(defun mc/make-cursor-overlay-inline (pos)
|
||||
"Create overlay to look like cursor inside text."
|
||||
(let ((overlay (make-overlay pos (1+ pos) nil nil nil)))
|
||||
(if (and mc/match-cursor-style (mc/cursor-is-bar))
|
||||
(if (mc/cursor-is-bar)
|
||||
(overlay-put overlay 'before-string (propertize "|" 'face 'mc/cursor-bar-face))
|
||||
(overlay-put overlay 'face 'mc/cursor-face))
|
||||
overlay))
|
||||
@@ -252,11 +238,8 @@ If this value is nil, there is no ceiling."
|
||||
:group 'multiple-cursors)
|
||||
|
||||
(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.
|
||||
|
||||
Saves the current state in the overlay
|
||||
to be restored later."
|
||||
"Add a fake cursor and possibly a fake active region overlay based on point and mark.
|
||||
Saves the current state in the overlay to be restored later."
|
||||
(unless mc--max-cursors-original
|
||||
(setq mc--max-cursors-original mc/max-cursors))
|
||||
(when mc/max-cursors
|
||||
@@ -276,8 +259,7 @@ to be restored later."
|
||||
overlay))
|
||||
|
||||
(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)
|
||||
(run-hooks 'pre-command-hook)
|
||||
(unless (eq this-command 'ignore)
|
||||
@@ -319,35 +301,28 @@ cursor with updated info."
|
||||
;; Intercept some reading commands so you won't have to
|
||||
;; answer them for every single cursor
|
||||
|
||||
(defvar mc--input-function-cache nil)
|
||||
(defvar mc--read-char 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 ()
|
||||
(setq mc--input-function-cache nil))
|
||||
(setq mc--read-char nil)
|
||||
(setq mc--read-quoted-char nil))
|
||||
|
||||
(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
|
||||
(mc--reset-read-prompts)
|
||||
|
||||
(defun mc/fake-cursor-p (o)
|
||||
"Predicate to check if an overlay is a fake cursor"
|
||||
@@ -362,10 +337,8 @@ values."
|
||||
(defvar mc--stored-state-for-undo nil
|
||||
"Variable to keep the state of the real cursor while undoing a fake one")
|
||||
|
||||
;;;###autoload
|
||||
(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)))
|
||||
(when cursor
|
||||
(setq mc--stored-state-for-undo (mc/store-current-state-in-overlay
|
||||
@@ -389,6 +362,310 @@ which action is being undone."
|
||||
:type '(boolean)
|
||||
: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))
|
||||
|
||||
;; 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))
|
||||
(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 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)))))))
|
||||
|
||||
(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)
|
||||
(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
|
||||
"Commands to run only once in multiple-cursors-mode.")
|
||||
|
||||
@@ -451,8 +728,6 @@ which action is being undone."
|
||||
redo
|
||||
undo-tree-undo
|
||||
undo-tree-redo
|
||||
undo-fu-only-undo
|
||||
undo-fu-only-redo
|
||||
universal-argument
|
||||
universal-argument-more
|
||||
universal-argument-other-key
|
||||
@@ -485,9 +760,6 @@ which action is being undone."
|
||||
windmove-down
|
||||
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
|
||||
"Default set of commands that should be mirrored by all cursors")
|
||||
|
||||
@@ -568,331 +840,8 @@ which action is being undone."
|
||||
smart-up
|
||||
smart-down))
|
||||
|
||||
(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
|
||||
(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 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) (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)))
|
||||
|
||||
(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 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)))))))
|
||||
|
||||
(defadvice execute-extended-command (after execute-extended-command-for-all-cursors () activate)
|
||||
(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)
|
||||
(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-for-all nil
|
||||
"Commands to run for all cursors in multiple-cursors-mode")
|
||||
|
||||
(provide 'multiple-cursors-core)
|
||||
(require 'mc-cycle-cursors)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
(define-package "multiple-cursors" "1.3.0"
|
||||
"Multiple cursors for Emacs."
|
||||
'((cl-lib "0.5")))
|
||||
+2
-3
@@ -3,10 +3,8 @@
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen
|
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com>
|
||||
;; Package-Version: 1.5.0
|
||||
;; Package-Requires: ((cl-lib "0.5"))
|
||||
;; Version: 1.4.0
|
||||
;; Keywords: editing cursors
|
||||
;; Homepage: https://github.com/magnars/multiple-cursors.el
|
||||
|
||||
;; This program is free software; you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
@@ -154,6 +152,7 @@
|
||||
|
||||
;; * isearch-forward and isearch-backward aren't supported with multiple cursors.
|
||||
;; You should feel free to add a simplified version that can work with it.
|
||||
;; * Commands run with `M-x` won't be repeated for all cursors.
|
||||
;; * All key bindings that refer to lambdas are always run for all cursors. If you
|
||||
;; need to limit it, you will have to give it a name.
|
||||
;; * Redo might screw with your cursors. Undo works very well.
|
||||
|
||||
@@ -52,9 +52,8 @@
|
||||
(defun set-rectangular-region-anchor ()
|
||||
"Anchors the rectangular region at point.
|
||||
|
||||
Think of this one as `set-mark' except you're marking a
|
||||
rectangular region. It is an exceedingly quick way of adding
|
||||
multiple cursors to multiple lines."
|
||||
Think of this one as `set-mark' except you're marking a rectangular region. It is
|
||||
an exceedingly quick way of adding multiple cursors to multiple lines."
|
||||
(interactive)
|
||||
(set-marker rrm/anchor (point))
|
||||
(push-mark (point))
|
||||
@@ -112,9 +111,7 @@ multiple cursors to multiple lines."
|
||||
;;;###autoload
|
||||
(define-minor-mode rectangular-region-mode
|
||||
"A mode for creating a rectangular region to edit"
|
||||
:init-value nil
|
||||
:lighter " rr"
|
||||
:keymap rectangular-region-mode-map
|
||||
nil " rr" rectangular-region-mode-map
|
||||
(if rectangular-region-mode
|
||||
(progn
|
||||
(add-hook 'after-change-functions 'rrm/switch-to-multiple-cursors t t)
|
||||
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh -e
|
||||
|
||||
cd "$(dirname "$0")"
|
||||
|
||||
ECUKES_EMACS=${EMACS:-$(which emacs)}
|
||||
export ECUKES_EMACS
|
||||
|
||||
echo "*** Emacs version ***"
|
||||
echo "ECUKES_EMACS = $ECUKES_EMACS"
|
||||
"$ECUKES_EMACS" --version
|
||||
echo
|
||||
|
||||
exec ./run-tests.sh $TAGS
|
||||
Reference in New Issue
Block a user