kj
3 years ago
21 changed files with 2 additions and 2766 deletions
@ -1,119 +0,0 @@
@@ -1,119 +0,0 @@
|
||||
;;; mc-cycle-cursors.el |
||||
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen |
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com> |
||||
;; Keywords: editing cursors |
||||
|
||||
;; This program is free software; you can redistribute it and/or modify |
||||
;; it under the terms of the GNU General Public License as published by |
||||
;; the Free Software Foundation, either version 3 of the License, or |
||||
;; (at your option) any later version. |
||||
|
||||
;; This program is distributed in the hope that it will be useful, |
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
;; GNU General Public License for more details. |
||||
|
||||
;; You should have received a copy of the GNU General Public License |
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
;;; Commentary: |
||||
|
||||
;; This scrolls the buffer to center each cursor in turn. |
||||
;; Scroll down with C-v, scroll up with M-v |
||||
;; This is nice when you have cursors that's outside of your view. |
||||
|
||||
;;; Code: |
||||
|
||||
(require 'multiple-cursors-core) |
||||
|
||||
(defun mc/next-fake-cursor-after-point () |
||||
(let ((pos (point)) |
||||
(next-pos (1+ (point-max))) |
||||
next) |
||||
(mc/for-each-fake-cursor |
||||
(let ((cursor-pos (overlay-get cursor 'point))) |
||||
(when (and (< pos cursor-pos) |
||||
(< cursor-pos next-pos)) |
||||
(setq next-pos cursor-pos) |
||||
(setq next cursor)))) |
||||
next)) |
||||
|
||||
(defun mc/prev-fake-cursor-before-point () |
||||
(let ((pos (point)) |
||||
(prev-pos (1- (point-min))) |
||||
prev) |
||||
(mc/for-each-fake-cursor |
||||
(let ((cursor-pos (overlay-get cursor 'point))) |
||||
(when (and (> pos cursor-pos) |
||||
(> cursor-pos prev-pos)) |
||||
(setq prev-pos cursor-pos) |
||||
(setq prev cursor)))) |
||||
prev)) |
||||
|
||||
(defcustom mc/cycle-looping-behaviour 'continue |
||||
"What to do if asked to cycle beyond the last cursor or before the first cursor." |
||||
:type '(radio (const :tag "Loop around to beginning/end of document." continue) |
||||
(const :tag "Warn and then loop around." warn) |
||||
(const :tag "Signal an error." error) |
||||
(const :tag "Don't loop." stop)) |
||||
:group 'multiple-cursors) |
||||
|
||||
(defun mc/handle-loop-condition (error-message) |
||||
(cl-ecase mc/cycle-looping-behaviour |
||||
(error (error error-message)) |
||||
(warn (message error-message)) |
||||
(continue 'continue) |
||||
(stop 'stop))) |
||||
|
||||
(defun mc/first-fake-cursor-after (point) |
||||
"Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)." |
||||
(let* ((cursors (mc/all-fake-cursors)) |
||||
(cursors-after-point (cl-remove-if (lambda (cursor) |
||||
(< (mc/cursor-beg cursor) point)) |
||||
cursors)) |
||||
(cursors-in-order (cl-sort cursors-after-point '< :key 'mc/cursor-beg))) |
||||
(car cursors-in-order))) |
||||
|
||||
(defun mc/last-fake-cursor-before (point) |
||||
"Very similar to mc/furthest-cursor-before-point, but ignores (mark) and (point)." |
||||
(let* ((cursors (mc/all-fake-cursors)) |
||||
(cursors-before-point (cl-remove-if (lambda (cursor) |
||||
(> (mc/cursor-end cursor) point)) |
||||
cursors)) |
||||
(cursors-in-order (cl-sort cursors-before-point '> :key 'mc/cursor-end))) |
||||
(car cursors-in-order))) |
||||
|
||||
(cl-defun mc/cycle (next-cursor fallback-cursor loop-message) |
||||
(when (null next-cursor) |
||||
(when (eql 'stop (mc/handle-loop-condition loop-message)) |
||||
(return-from mc/cycle nil)) |
||||
(setf next-cursor fallback-cursor)) |
||||
(mc/create-fake-cursor-at-point) |
||||
(mc/pop-state-from-overlay next-cursor) |
||||
(recenter)) |
||||
|
||||
(defun mc/cycle-forward () |
||||
(interactive) |
||||
(mc/cycle (mc/next-fake-cursor-after-point) |
||||
(mc/first-fake-cursor-after (point-min)) |
||||
"We're already at the last cursor.")) |
||||
|
||||
(defun mc/cycle-backward () |
||||
(interactive) |
||||
(mc/cycle (mc/prev-fake-cursor-before-point) |
||||
(mc/last-fake-cursor-before (point-max)) |
||||
"We're already at the last cursor")) |
||||
|
||||
(define-key mc/keymap (kbd "C-v") 'mc/cycle-forward) |
||||
(define-key mc/keymap (kbd "M-v") 'mc/cycle-backward) |
||||
|
||||
(provide 'mc-cycle-cursors) |
||||
|
||||
|
||||
;; Local Variables: |
||||
;; coding: utf-8 |
||||
;; End: |
||||
|
||||
;;; mc-cycle-cursors.el ends here |
Binary file not shown.
@ -1,110 +0,0 @@
@@ -1,110 +0,0 @@
|
||||
;;; mc-edit-lines.el |
||||
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen |
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com> |
||||
;; Keywords: editing cursors |
||||
|
||||
;; This program is free software; you can redistribute it and/or modify |
||||
;; it under the terms of the GNU General Public License as published by |
||||
;; the Free Software Foundation, either version 3 of the License, or |
||||
;; (at your option) any later version. |
||||
|
||||
;; This program is distributed in the hope that it will be useful, |
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
;; GNU General Public License for more details. |
||||
|
||||
;; You should have received a copy of the GNU General Public License |
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
;;; Commentary: |
||||
|
||||
;; This file contains functions to add multiple cursors to consecutive lines |
||||
;; given an active region. |
||||
|
||||
;; Please see multiple-cursors.el for more commentary. |
||||
|
||||
;;; Code: |
||||
|
||||
(require 'multiple-cursors-core) |
||||
|
||||
(defcustom mc/edit-lines-empty-lines nil |
||||
"What should be done by `mc/edit-lines' when a line is not long enough." |
||||
:type '(radio (const :tag "Pad the line with spaces." pad) |
||||
(const :tag "Ignore the line." ignore) |
||||
(const :tag "Signal an error." error) |
||||
(const :tag "Nothing. Cursor is at end of line." nil)) |
||||
:group 'multiple-cursors) |
||||
|
||||
;;;###autoload |
||||
(defun mc/edit-lines (&optional arg) |
||||
"Add one cursor to each line of the active region. |
||||
Starts from mark and moves in straight down or up towards the |
||||
line point is on. |
||||
|
||||
What is done with lines which are not long enough is governed by |
||||
`mc/edit-lines-empty-lines'. The prefix argument ARG can be used |
||||
to override this. If ARG is a symbol (when called from Lisp), |
||||
that symbol is used instead of `mc/edit-lines-empty-lines'. |
||||
Otherwise, if ARG negative, short lines will be ignored. Any |
||||
other non-nil value will cause short lines to be padded." |
||||
(interactive "P") |
||||
(when (not (and mark-active (/= (point) (mark)))) |
||||
(error "Mark a set of lines first")) |
||||
(mc/remove-fake-cursors) |
||||
(let* ((col (current-column)) |
||||
(point-line (mc/line-number-at-pos)) |
||||
(mark-line (progn (exchange-point-and-mark) (mc/line-number-at-pos))) |
||||
(direction (if (< point-line mark-line) :up :down)) |
||||
(style (cond |
||||
;; called from lisp |
||||
((and arg (symbolp arg)) |
||||
arg) |
||||
;; negative argument |
||||
((< (prefix-numeric-value arg) 0) |
||||
'ignore) |
||||
(arg 'pad) |
||||
(t mc/edit-lines-empty-lines)))) |
||||
(deactivate-mark) |
||||
(when (and (eq direction :up) (bolp)) |
||||
(previous-logical-line 1 nil) |
||||
(move-to-column col)) |
||||
;; Add the cursors |
||||
(while (not (eq (mc/line-number-at-pos) point-line)) |
||||
;; Pad the line |
||||
(when (eq style 'pad) |
||||
(while (< (current-column) col) |
||||
(insert " "))) |
||||
;; Error |
||||
(when (and (eq style 'error) |
||||
(not (equal col (current-column)))) |
||||
(error "Short line encountered in `mc/edit-lines'")) |
||||
;; create the cursor |
||||
(unless (and (eq style 'ignore) |
||||
(not (equal col (current-column)))) |
||||
(mc/create-fake-cursor-at-point)) |
||||
;; proceed to next |
||||
(if (eq direction :up) |
||||
(previous-logical-line 1 nil) |
||||
(next-logical-line 1 nil)) |
||||
(move-to-column col)) |
||||
(multiple-cursors-mode))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/edit-ends-of-lines () |
||||
"Add one cursor to the end of each line in the active region." |
||||
(interactive) |
||||
(mc/edit-lines) |
||||
(mc/execute-command-for-all-cursors 'end-of-line)) |
||||
|
||||
;;;###autoload |
||||
(defun mc/edit-beginnings-of-lines () |
||||
"Add one cursor to the beginning of each line in the active region." |
||||
(interactive) |
||||
(mc/edit-lines) |
||||
(mc/execute-command-for-all-cursors 'beginning-of-line)) |
||||
|
||||
(provide 'mc-edit-lines) |
||||
|
||||
;;; mc-edit-lines.el ends here |
Binary file not shown.
@ -1,107 +0,0 @@
@@ -1,107 +0,0 @@
|
||||
;;; mc-hide-unmatched-lines.el |
||||
|
||||
;; Copyright (C) 2014 Aleksey Fedotov |
||||
|
||||
;; Author: Aleksey Fedotov <lexa@cfotr.com> |
||||
;; Keywords: editing cursors |
||||
|
||||
;; This program is free software; you can redistribute it and/or modify |
||||
;; it under the terms of the GNU General Public License as published by |
||||
;; the Free Software Foundation, either version 3 of the License, or |
||||
;; (at your option) any later version. |
||||
|
||||
;; This program is distributed in the hope that it will be useful, |
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
;; GNU General Public License for more details. |
||||
|
||||
;; You should have received a copy of the GNU General Public License |
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
;;; Commentary: |
||||
|
||||
;; This minor mode when enabled hides all lines where no cursors (and |
||||
;; also hum/lines-to-expand below and above) To make use of this mode |
||||
;; press "C-'" while multiple-cursor-mode is active. You can still |
||||
;; edit lines while you are in mc-hide-unmatched-lines mode. To leave |
||||
;; this mode press "<return>" or "C-g" |
||||
;; |
||||
|
||||
;;; Code: |
||||
|
||||
(require 'multiple-cursors-core) |
||||
(require 'mc-mark-more) |
||||
|
||||
(defvar hum/hide-unmatched-lines-mode-map (make-sparse-keymap) |
||||
"Keymap for hide unmatched lines is mainly for rebinding C-g") |
||||
|
||||
(define-key hum/hide-unmatched-lines-mode-map (kbd "C-g") 'hum/keyboard-quit) |
||||
(define-key hum/hide-unmatched-lines-mode-map (kbd "<return>") 'hum/keyboard-quit) |
||||
|
||||
(defun hum/keyboard-quit () |
||||
"Leave hide-unmatched-lines mode" |
||||
(interactive) |
||||
(mc-hide-unmatched-lines-mode 0)) |
||||
|
||||
;; used only in in multiple-cursors-mode-disabled-hook |
||||
(defun hum/disable-hum-mode () |
||||
(mc-hide-unmatched-lines-mode 0)) |
||||
|
||||
;;;###autoload |
||||
(define-minor-mode mc-hide-unmatched-lines-mode |
||||
"Minor mode when enabled hides all lines where no cursors (and |
||||
also hum/lines-to-expand below and above) To make use of this |
||||
mode press \"C-'\" while multiple-cursor-mode is active. You can |
||||
still edit lines while you are in mc-hide-unmatched-lines |
||||
mode. To leave this mode press <return> or \"C-g\"" |
||||
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 |
||||
(hum/hide-unmatched-lines) |
||||
(add-hook 'multiple-cursors-mode-disabled-hook 'hum/disable-hum-mode t t)) |
||||
(progn |
||||
(hum/unhide-unmatched-lines) |
||||
(remove-hook 'multiple-cursors-mode-disabled-hook 'hum/disable-hum-mode)))) |
||||
|
||||
(defconst hum/invisible-overlay-name 'hum/invisible-overlay-name) |
||||
|
||||
(defcustom hum/lines-to-expand 2 |
||||
"How many lines below and above cursor to show" |
||||
:type '(integer) |
||||
:group 'multiple-cursors) |
||||
|
||||
(defcustom hum/placeholder "..." |
||||
"Placeholder which will be placed instead of hidden text" |
||||
:type '(string) |
||||
:group 'multiple-cursors) |
||||
|
||||
(defun hum/add-invisible-overlay (begin end) |
||||
(let ((overlay (make-overlay begin |
||||
end |
||||
(current-buffer) |
||||
t |
||||
nil |
||||
))) |
||||
(overlay-put overlay hum/invisible-overlay-name t) |
||||
(overlay-put overlay 'invisible t) |
||||
(overlay-put overlay 'intangible t) |
||||
(overlay-put overlay 'evaporate t) |
||||
(overlay-put overlay 'after-string hum/placeholder))) |
||||
|
||||
(defun hum/hide-unmatched-lines () |
||||
(let ((begin (point-min))) |
||||
(mc/for-each-cursor-ordered |
||||
(save-excursion |
||||
(goto-char (mc/cursor-beg cursor)) |
||||
(if (< begin (line-beginning-position (- hum/lines-to-expand))) |
||||
(hum/add-invisible-overlay begin (line-end-position (- hum/lines-to-expand)))) |
||||
(setq begin (line-beginning-position (+ 2 hum/lines-to-expand))))) |
||||
(hum/add-invisible-overlay begin (point-max)))) |
||||
|
||||
(defun hum/unhide-unmatched-lines () |
||||
(remove-overlays nil nil hum/invisible-overlay-name t)) |
||||
|
||||
(provide 'mc-hide-unmatched-lines-mode) |
||||
(define-key mc/keymap (kbd "C-'") 'mc-hide-unmatched-lines-mode) |
Binary file not shown.
@ -1,709 +0,0 @@
@@ -1,709 +0,0 @@
|
||||
;;; mc-mark-more.el |
||||
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen |
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com> |
||||
;; Keywords: editing cursors |
||||
|
||||
;; This program is free software; you can redistribute it and/or modify |
||||
;; it under the terms of the GNU General Public License as published by |
||||
;; the Free Software Foundation, either version 3 of the License, or |
||||
;; (at your option) any later version. |
||||
|
||||
;; This program is distributed in the hope that it will be useful, |
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
;; GNU General Public License for more details. |
||||
|
||||
;; You should have received a copy of the GNU General Public License |
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
;;; Commentary: |
||||
|
||||
;; This file contains functions to mark more parts of the buffer. |
||||
;; See ./features/mark-more.feature for examples. |
||||
|
||||
;; Please see multiple-cursors.el for more commentary. |
||||
|
||||
;;; Code: |
||||
|
||||
(require 'multiple-cursors-core) |
||||
(require 'thingatpt) |
||||
|
||||
(defun mc/cursor-end (cursor) |
||||
(if (overlay-get cursor 'mark-active) |
||||
(max (overlay-get cursor 'point) |
||||
(overlay-get cursor 'mark)) |
||||
(overlay-get cursor 'point))) |
||||
|
||||
(defun mc/cursor-beg (cursor) |
||||
(if (overlay-get cursor 'mark-active) |
||||
(min (overlay-get cursor 'point) |
||||
(overlay-get cursor 'mark)) |
||||
(overlay-get cursor 'point))) |
||||
|
||||
(defun mc/furthest-region-end () |
||||
(let ((end (max (mark) (point)))) |
||||
(mc/for-each-fake-cursor |
||||
(setq end (max end (mc/cursor-end cursor)))) |
||||
end)) |
||||
|
||||
(defun mc/first-region-start () |
||||
(let ((beg (min (mark) (point)))) |
||||
(mc/for-each-fake-cursor |
||||
(setq beg (min beg (mc/cursor-beg cursor)))) |
||||
beg)) |
||||
|
||||
(defun mc/furthest-cursor-before-point () |
||||
(let ((beg (if mark-active (min (mark) (point)) (point))) |
||||
furthest) |
||||
(mc/for-each-fake-cursor |
||||
(when (< (mc/cursor-beg cursor) beg) |
||||
(setq beg (mc/cursor-beg cursor)) |
||||
(setq furthest cursor))) |
||||
furthest)) |
||||
|
||||
(defun mc/furthest-cursor-after-point () |
||||
(let ((end (if mark-active (max (mark) (point)) (point))) |
||||
furthest) |
||||
(mc/for-each-fake-cursor |
||||
(when (> (mc/cursor-end cursor) end) |
||||
(setq end (mc/cursor-end cursor)) |
||||
(setq furthest cursor))) |
||||
furthest)) |
||||
|
||||
(defun mc/fake-cursor-at-point (&optional point) |
||||
"Return the fake cursor with its point right at POINT (defaults |
||||
to (point)), or nil." |
||||
(setq point (or point (point))) |
||||
(let ((cursors (mc/all-fake-cursors)) |
||||
(c nil)) |
||||
(catch 'found |
||||
(while (setq c (pop cursors)) |
||||
(when (eq (marker-position (overlay-get c 'point)) |
||||
point) |
||||
(throw 'found c)))))) |
||||
|
||||
(defun mc/region-strings () |
||||
(let ((strings (list (buffer-substring-no-properties (point) (mark))))) |
||||
(mc/for-each-fake-cursor |
||||
(add-to-list 'strings (buffer-substring-no-properties |
||||
(mc/cursor-beg cursor) |
||||
(mc/cursor-end cursor)))) |
||||
strings)) |
||||
|
||||
(defvar mc/enclose-search-term nil |
||||
"How should mc/mark-more-* search for more matches? |
||||
|
||||
Match everything: nil |
||||
Match only whole words: 'words |
||||
Match only whole symbols: 'symbols |
||||
|
||||
Use like case-fold-search, don't recommend setting it globally.") |
||||
|
||||
(defun mc/mark-more-like-this (skip-last direction) |
||||
(let ((case-fold-search nil) |
||||
(re (regexp-opt (mc/region-strings) mc/enclose-search-term)) |
||||
(point-out-of-order (cl-ecase direction |
||||
(forwards (< (point) (mark))) |
||||
(backwards (not (< (point) (mark)))))) |
||||
(furthest-cursor (cl-ecase direction |
||||
(forwards (mc/furthest-cursor-after-point)) |
||||
(backwards (mc/furthest-cursor-before-point)))) |
||||
(start-char (cl-ecase direction |
||||
(forwards (mc/furthest-region-end)) |
||||
(backwards (mc/first-region-start)))) |
||||
(search-function (cl-ecase direction |
||||
(forwards 'search-forward-regexp) |
||||
(backwards 'search-backward-regexp))) |
||||
(match-point-getter (cl-ecase direction |
||||
(forwards 'match-beginning) |
||||
(backwards 'match-end)))) |
||||
(if (and skip-last (not furthest-cursor)) |
||||
(error "No cursors to be skipped") |
||||
(mc/save-excursion |
||||
(goto-char start-char) |
||||
(when skip-last |
||||
(mc/remove-fake-cursor furthest-cursor)) |
||||
(if (funcall search-function re nil t) |
||||
(progn |
||||
(push-mark (funcall match-point-getter 0)) |
||||
(when point-out-of-order |
||||
(exchange-point-and-mark)) |
||||
(mc/create-fake-cursor-at-point)) |
||||
(user-error "no more matches found.")))))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-next-like-this (arg) |
||||
"Find and mark the next part of the buffer matching the currently active region |
||||
If no region is active add a cursor on the next line |
||||
With negative ARG, delete the last one instead. |
||||
With zero ARG, skip the last one and mark next." |
||||
(interactive "p") |
||||
(if (< arg 0) |
||||
(let ((cursor (mc/furthest-cursor-after-point))) |
||||
(if cursor |
||||
(mc/remove-fake-cursor cursor) |
||||
(error "No cursors to be unmarked"))) |
||||
(if (region-active-p) |
||||
(mc/mark-more-like-this (= arg 0) 'forwards) |
||||
(mc/mark-lines arg 'forwards))) |
||||
(mc/maybe-multiple-cursors-mode)) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-next-like-this-word (arg) |
||||
"Find and mark the next part of the buffer matching the currently active region |
||||
If no region is active, mark the word at the point and find the next match |
||||
With negative ARG, delete the last one instead. |
||||
With zero ARG, skip the last one and mark next." |
||||
(interactive "p") |
||||
(if (< arg 0) |
||||
(let ((cursor (mc/furthest-cursor-after-point))) |
||||
(if cursor |
||||
(mc/remove-fake-cursor cursor) |
||||
(error "No cursors to be unmarked"))) |
||||
(if (region-active-p) |
||||
(mc/mark-more-like-this (= arg 0) 'forwards) |
||||
(mc--select-thing-at-point 'word) |
||||
(mc/mark-more-like-this (= arg 0) 'forwards))) |
||||
(mc/maybe-multiple-cursors-mode)) |
||||
|
||||
(defun mc/mark-next-like-this-symbol (arg) |
||||
"Find and mark the next part of the buffer matching the currently active region |
||||
If no region is active, mark the symbol at the point and find the next match |
||||
With negative ARG, delete the last one instead. |
||||
With zero ARG, skip the last one and mark next." |
||||
(interactive "p") |
||||
(if (< arg 0) |
||||
(let ((cursor (mc/furthest-cursor-after-point))) |
||||
(if cursor |
||||
(mc/remove-fake-cursor cursor) |
||||
(error "No cursors to be unmarked"))) |
||||
(if (region-active-p) |
||||
(mc/mark-more-like-this (= arg 0) 'forwards) |
||||
(mc--select-thing-at-point 'symbol) |
||||
(mc/mark-more-like-this (= arg 0) 'forwards))) |
||||
(mc/maybe-multiple-cursors-mode)) |
||||
|
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-next-word-like-this (arg) |
||||
"Find and mark the next word of the buffer matching the currently active region |
||||
The matching region must be a whole word to be a match |
||||
If no region is active, mark the symbol at the point and find the next match |
||||
With negative ARG, delete the last one instead. |
||||
With zero ARG, skip the last one and mark next." |
||||
(interactive "p") |
||||
(let ((mc/enclose-search-term 'words)) |
||||
(mc/mark-next-like-this arg))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-next-symbol-like-this (arg) |
||||
"Find and mark the next symbol of the buffer matching the currently active region |
||||
The matching region must be a whole symbol to be a match |
||||
If no region is active, mark the symbol at the point and find the next match |
||||
With negative ARG, delete the last one instead. |
||||
With zero ARG, skip the last one and mark next." |
||||
(interactive "p") |
||||
(let ((mc/enclose-search-term 'symbols)) |
||||
(mc/mark-next-like-this arg))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-previous-like-this (arg) |
||||
"Find and mark the previous part of the buffer matching the currently active region |
||||
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) |
||||
(let ((cursor (mc/furthest-cursor-before-point))) |
||||
(if cursor |
||||
(mc/remove-fake-cursor cursor) |
||||
(error "No cursors to be unmarked"))) |
||||
(if (region-active-p) |
||||
(mc/mark-more-like-this (= arg 0) 'backwards) |
||||
(mc/mark-lines arg 'backwards))) |
||||
(mc/maybe-multiple-cursors-mode)) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-previous-like-this-word (arg) |
||||
"Find and mark the previous part of the buffer matching the currently active region |
||||
If no region is active, mark the word at the point and find the previous match |
||||
With negative ARG, delete the last one instead. |
||||
With zero ARG, skip the last one and mark previous." |
||||
(interactive "p") |
||||
(if (< arg 0) |
||||
(let ((cursor (mc/furthest-cursor-after-point))) |
||||
(if cursor |
||||
(mc/remove-fake-cursor cursor) |
||||
(error "No cursors to be unmarked"))) |
||||
(if (region-active-p) |
||||
(mc/mark-more-like-this (= arg 0) 'backwards) |
||||
(mc--select-thing-at-point 'word) |
||||
(mc/mark-more-like-this (= arg 0) 'backwards))) |
||||
(mc/maybe-multiple-cursors-mode)) |
||||
|
||||
(defun mc/mark-previous-like-this-symbol (arg) |
||||
"Find and mark the previous part of the buffer matching the currently active region |
||||
If no region is active, mark the symbol at the point and find the previous match |
||||
With negative ARG, delete the last one instead. |
||||
With zero ARG, skip the last one and mark previous." |
||||
(interactive "p") |
||||
(if (< arg 0) |
||||
(let ((cursor (mc/furthest-cursor-after-point))) |
||||
(if cursor |
||||
(mc/remove-fake-cursor cursor) |
||||
(error "No cursors to be unmarked"))) |
||||
(if (region-active-p) |
||||
(mc/mark-more-like-this (= arg 0) 'backwards) |
||||
(mc--select-thing-at-point 'symbol) |
||||
(mc/mark-more-like-this (= arg 0) 'backwards))) |
||||
(mc/maybe-multiple-cursors-mode)) |
||||
|
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-previous-word-like-this (arg) |
||||
"Find and mark the previous part of the buffer matching the currently active region |
||||
The matching region must be a whole word to be a match |
||||
If no region is active add a cursor on the previous line |
||||
With negative ARG, delete the last one instead. |
||||
With zero ARG, skip the last one and mark next." |
||||
(interactive "p") |
||||
(let ((mc/enclose-search-term 'words)) |
||||
(mc/mark-previous-like-this arg))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-previous-symbol-like-this (arg) |
||||
"Find and mark the previous part of the buffer matching the currently active region |
||||
The matching region must be a whole symbol to be a match |
||||
If no region is active add a cursor on the previous line |
||||
With negative ARG, delete the last one instead. |
||||
With zero ARG, skip the last one and mark next." |
||||
(interactive "p") |
||||
(let ((mc/enclose-search-term 'symbols)) |
||||
(mc/mark-previous-like-this arg))) |
||||
|
||||
(defun mc/mark-lines (num-lines direction) |
||||
(dotimes (i (if (= num-lines 0) 1 num-lines)) |
||||
(mc/save-excursion |
||||
(let ((furthest-cursor (cl-ecase direction |
||||
(forwards (mc/furthest-cursor-after-point)) |
||||
(backwards (mc/furthest-cursor-before-point))))) |
||||
(when (overlayp furthest-cursor) |
||||
(goto-char (overlay-get furthest-cursor 'point)) |
||||
(when (= num-lines 0) |
||||
(mc/remove-fake-cursor furthest-cursor)))) |
||||
(cl-ecase direction |
||||
(forwards (next-logical-line 1 nil)) |
||||
(backwards (previous-logical-line 1 nil))) |
||||
(mc/create-fake-cursor-at-point)))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-next-lines (arg) |
||||
(interactive "p") |
||||
(mc/mark-lines arg 'forwards) |
||||
(mc/maybe-multiple-cursors-mode)) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-previous-lines (arg) |
||||
(interactive "p") |
||||
(mc/mark-lines arg 'backwards) |
||||
(mc/maybe-multiple-cursors-mode)) |
||||
|
||||
;;;###autoload |
||||
(defun mc/unmark-next-like-this () |
||||
"Deselect next part of the buffer matching the currently active region." |
||||
(interactive) |
||||
(mc/mark-next-like-this -1)) |
||||
|
||||
;;;###autoload |
||||
(defun mc/unmark-previous-like-this () |
||||
"Deselect prev part of the buffer matching the currently active region." |
||||
(interactive) |
||||
(mc/mark-previous-like-this -1)) |
||||
|
||||
;;;###autoload |
||||
(defun mc/skip-to-next-like-this () |
||||
"Skip the current one and select the next part of the buffer matching the currently active region." |
||||
(interactive) |
||||
(mc/mark-next-like-this 0)) |
||||
|
||||
;;;###autoload |
||||
(defun mc/skip-to-previous-like-this () |
||||
"Skip the current one and select the prev part of the buffer matching the currently active region." |
||||
(interactive) |
||||
(mc/mark-previous-like-this 0)) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-all-like-this () |
||||
"Find and mark all the parts of the buffer matching the currently active region" |
||||
(interactive) |
||||
(unless (region-active-p) |
||||
(error "Mark a region to match first.")) |
||||
(mc/remove-fake-cursors) |
||||
(let ((master (point)) |
||||
(case-fold-search nil) |
||||
(point-first (< (point) (mark))) |
||||
(re (regexp-opt (mc/region-strings) mc/enclose-search-term))) |
||||
(mc/save-excursion |
||||
(goto-char 0) |
||||
(while (search-forward-regexp re nil t) |
||||
(push-mark (match-beginning 0)) |
||||
(when point-first (exchange-point-and-mark)) |
||||
(unless (= master (point)) |
||||
(mc/create-fake-cursor-at-point)) |
||||
(when point-first (exchange-point-and-mark))))) |
||||
(if (> (mc/num-cursors) 1) |
||||
(multiple-cursors-mode 1) |
||||
(multiple-cursors-mode 0))) |
||||
|
||||
(defun mc--select-thing-at-point (thing) |
||||
(let ((bound (bounds-of-thing-at-point thing))) |
||||
(when bound |
||||
(set-mark (car bound)) |
||||
(goto-char (cdr bound)) |
||||
bound))) |
||||
|
||||
(defun mc--select-thing-at-point-or-bark (thing) |
||||
(unless (or (region-active-p) (mc--select-thing-at-point thing)) |
||||
(error "Mark a region or set cursor on a %s." thing))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-all-words-like-this () |
||||
(interactive) |
||||
(mc--select-thing-at-point-or-bark 'word) |
||||
(let ((mc/enclose-search-term 'words)) |
||||
(mc/mark-all-like-this))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-all-symbols-like-this () |
||||
(interactive) |
||||
(mc--select-thing-at-point-or-bark 'symbol) |
||||
(let ((mc/enclose-search-term 'symbols)) |
||||
(mc/mark-all-like-this))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-all-in-region (beg end &optional search) |
||||
"Find and mark all the parts in the region matching the given search" |
||||
(interactive "r") |
||||
(let ((search (or search (read-from-minibuffer "Mark all in region: "))) |
||||
(case-fold-search nil)) |
||||
(if (string= search "") |
||||
(message "Mark aborted") |
||||
(progn |
||||
(mc/remove-fake-cursors) |
||||
(goto-char beg) |
||||
(while (search-forward search end t) |
||||
(push-mark (match-beginning 0)) |
||||
(mc/create-fake-cursor-at-point)) |
||||
(let ((first (mc/furthest-cursor-before-point))) |
||||
(if (not first) |
||||
(error "Search failed for %S" search) |
||||
(mc/pop-state-from-overlay first))) |
||||
(if (> (mc/num-cursors) 1) |
||||
(multiple-cursors-mode 1) |
||||
(multiple-cursors-mode 0)))))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-all-in-region-regexp (beg end) |
||||
"Find and mark all the parts in the region matching the given regexp." |
||||
(interactive "r") |
||||
(let ((search (read-regexp "Mark regexp in region: ")) |
||||
(case-fold-search nil)) |
||||
(if (string= search "") |
||||
(message "Mark aborted") |
||||
(progn |
||||
(mc/remove-fake-cursors) |
||||
(goto-char beg) |
||||
(let ((lastmatch)) |
||||
(while (and (< (point) end) ; can happen because of (forward-char) |
||||
(search-forward-regexp search end t)) |
||||
(push-mark (match-beginning 0)) |
||||
(mc/create-fake-cursor-at-point) |
||||
(setq lastmatch (point)) |
||||
(when (= (point) (match-beginning 0)) |
||||
(forward-char))) |
||||
(unless lastmatch |
||||
(error "Search failed for %S" search))) |
||||
(goto-char (match-end 0)) |
||||
(if (< (mc/num-cursors) 3) |
||||
(multiple-cursors-mode 0) |
||||
(mc/pop-state-from-overlay (mc/furthest-cursor-before-point)) |
||||
(multiple-cursors-mode 1)))))) |
||||
|
||||
(when (not (fboundp 'set-temporary-overlay-map)) |
||||
;; Backport this function from newer emacs versions |
||||
(defun set-temporary-overlay-map (map &optional keep-pred) |
||||
"Set a new keymap that will only exist for a short period of time. |
||||
The new keymap to use must be given in the MAP variable. When to |
||||
remove the keymap depends on user input and KEEP-PRED: |
||||
|
||||
- if KEEP-PRED is nil (the default), the keymap disappears as |
||||
soon as any key is pressed, whether or not the key is in MAP; |
||||
|
||||
- if KEEP-PRED is t, the keymap disappears as soon as a key *not* |
||||
in MAP is pressed; |
||||
|
||||
- otherwise, KEEP-PRED must be a 0-arguments predicate that will |
||||
decide if the keymap should be removed (if predicate returns |
||||
nil) or kept (otherwise). The predicate will be called after |
||||
each key sequence." |
||||
|
||||
(let* ((clearfunsym (make-symbol "clear-temporary-overlay-map")) |
||||
(overlaysym (make-symbol "t")) |
||||
(alist (list (cons overlaysym map))) |
||||
(clearfun |
||||
`(lambda () |
||||
(unless ,(cond ((null keep-pred) nil) |
||||
((eq t keep-pred) |
||||
`(eq this-command |
||||
(lookup-key ',map |
||||
(this-command-keys-vector)))) |
||||
(t `(funcall ',keep-pred))) |
||||
(remove-hook 'pre-command-hook ',clearfunsym) |
||||
(setq emulation-mode-map-alists |
||||
(delq ',alist emulation-mode-map-alists)))))) |
||||
(set overlaysym overlaysym) |
||||
(fset clearfunsym clearfun) |
||||
(add-hook 'pre-command-hook clearfunsym) |
||||
|
||||
(push alist emulation-mode-map-alists)))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-more-like-this-extended () |
||||
"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 |
||||
|
||||
If direction is 'up: |
||||
|
||||
<left> Skip past the cursor furthest up |
||||
<right> Remove the cursor furthest up |
||||
|
||||
If direction is 'down: |
||||
|
||||
<left> Remove the cursor furthest down |
||||
<right> Skip past the cursor furthest down |
||||
|
||||
The bindings for these commands can be changed. See `mc/mark-more-like-this-extended-keymap'." |
||||
(interactive) |
||||
(mc/mmlte--down) |
||||
(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?") |
||||
|
||||
(make-variable-buffer-local 'mc/mark-more-like-this-extended) |
||||
|
||||
(defun mc/mmlte--message () |
||||
(if (eq mc/mark-more-like-this-extended-direction 'up) |
||||
(message "<up> to mark previous, <left> to skip, <right> to remove, <down> to mark next") |
||||
(message "<down> to mark next, <right> to skip, <left> to remove, <up> to mark previous"))) |
||||
|
||||
(defun mc/mmlte--up () |
||||
(interactive) |
||||
(mc/mark-previous-like-this 1) |
||||
(setq mc/mark-more-like-this-extended-direction 'up) |
||||
(mc/mmlte--message)) |
||||
|
||||
(defun mc/mmlte--down () |
||||
(interactive) |
||||
(mc/mark-next-like-this 1) |
||||
(setq mc/mark-more-like-this-extended-direction 'down) |
||||
(mc/mmlte--message)) |
||||
|
||||
(defun mc/mmlte--left () |
||||
(interactive) |
||||
(if (eq mc/mark-more-like-this-extended-direction 'down) |
||||
(mc/unmark-next-like-this) |
||||
(mc/skip-to-previous-like-this)) |
||||
(mc/mmlte--message)) |
||||
|
||||
(defun mc/mmlte--right () |
||||
(interactive) |
||||
(if (eq mc/mark-more-like-this-extended-direction 'up) |
||||
(mc/unmark-previous-like-this) |
||||
(mc/skip-to-next-like-this)) |
||||
(mc/mmlte--message)) |
||||
|
||||
(defvar mc/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 |
||||
(defun mc/mark-all-like-this-dwim (arg) |
||||
"Tries to guess what you want to mark all of. |
||||
Can be pressed multiple times to increase selection. |
||||
|
||||
With prefix, it behaves the same as original `mc/mark-all-like-this'" |
||||
(interactive "P") |
||||
(if arg |
||||
(mc/mark-all-like-this) |
||||
(if (and (not (use-region-p)) |
||||
(derived-mode-p 'sgml-mode) |
||||
(mc--on-tag-name-p)) |
||||
(mc/mark-sgml-tag-pair) |
||||
(let ((before (mc/num-cursors))) |
||||
(unless (eq last-command 'mc/mark-all-like-this-dwim) |
||||
(setq mc--restrict-mark-all-to-symbols nil)) |
||||
(unless (use-region-p) |
||||
(mc--mark-symbol-at-point) |
||||
(setq mc--restrict-mark-all-to-symbols t)) |
||||
(if mc--restrict-mark-all-to-symbols |
||||
(mc/mark-all-symbols-like-this-in-defun) |
||||
(mc/mark-all-like-this-in-defun)) |
||||
(when (<= (mc/num-cursors) before) |
||||
(if mc--restrict-mark-all-to-symbols |
||||
(mc/mark-all-symbols-like-this) |
||||
(mc/mark-all-like-this))) |
||||
(when (<= (mc/num-cursors) before) |
||||
(mc/mark-all-like-this)))))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-all-dwim (arg) |
||||
"Tries even harder to guess what you want to mark all of. |
||||
|
||||
If the region is active and spans multiple lines, it will behave |
||||
as if `mc/mark-all-in-region'. With the prefix ARG, it will call |
||||
`mc/edit-lines' instead. |
||||
|
||||
If the region is inactive or on a single line, it will behave like |
||||
`mc/mark-all-like-this-dwim'." |
||||
(interactive "P") |
||||
(if (and (use-region-p) |
||||
(not (> (mc/num-cursors) 1)) |
||||
(not (= (mc/line-number-at-pos (region-beginning)) |
||||
(mc/line-number-at-pos (region-end))))) |
||||
(if arg |
||||
(call-interactively 'mc/edit-lines) |
||||
(call-interactively 'mc/mark-all-in-region)) |
||||
(progn |
||||
(setq this-command 'mc/mark-all-like-this-dwim) |
||||
(mc/mark-all-like-this-dwim arg)))) |
||||
|
||||
(defun mc--in-defun () |
||||
(bounds-of-thing-at-point 'defun)) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-all-like-this-in-defun () |
||||
"Mark all like this in defun." |
||||
(interactive) |
||||
(if (mc--in-defun) |
||||
(save-restriction |
||||
(widen) |
||||
(narrow-to-defun) |
||||
(mc/mark-all-like-this)) |
||||
(mc/mark-all-like-this))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-all-words-like-this-in-defun () |
||||
"Mark all words like this in defun." |
||||
(interactive) |
||||
(mc--select-thing-at-point-or-bark 'word) |
||||
(if (mc--in-defun) |
||||
(save-restriction |
||||
(widen) |
||||
(narrow-to-defun) |
||||
(mc/mark-all-words-like-this)) |
||||
(mc/mark-all-words-like-this))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-all-symbols-like-this-in-defun () |
||||
"Mark all symbols like this in defun." |
||||
(interactive) |
||||
(mc--select-thing-at-point-or-bark 'symbol) |
||||
(if (mc--in-defun) |
||||
(save-restriction |
||||
(widen) |
||||
(narrow-to-defun) |
||||
(mc/mark-all-symbols-like-this)) |
||||
(mc/mark-all-symbols-like-this))) |
||||
|
||||
(defun mc--mark-symbol-at-point () |
||||
"Select the symbol under cursor" |
||||
(interactive) |
||||
(when (not (use-region-p)) |
||||
(let ((b (bounds-of-thing-at-point 'symbol))) |
||||
(goto-char (car b)) |
||||
(set-mark (cdr b))))) |
||||
|
||||
(defun mc--get-nice-sgml-context () |
||||
(car |
||||
(last |
||||
(progn |
||||
(when (looking-at "<") (forward-char 1)) |
||||
(when (looking-back ">") (forward-char -1)) |
||||
(sgml-get-context))))) |
||||
|
||||
(defun mc--on-tag-name-p () |
||||
(let* ((context (save-excursion (mc--get-nice-sgml-context))) |
||||
(tag-name-len (length (aref context 4))) |
||||
(beg (aref context 2)) |
||||
(end (+ beg tag-name-len (if (eq 'open (aref context 1)) 1 3)))) |
||||
(and context |
||||
(>= (point) beg) |
||||
(<= (point) end)))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/toggle-cursor-on-click (event) |
||||
"Add a cursor where you click, or remove a fake cursor that is |
||||
already there." |
||||
(interactive "e") |
||||
(mouse-minibuffer-check event) |
||||
;; Use event-end in case called from mouse-drag-region. |
||||
;; If EVENT is a click, event-end and event-start give same value. |
||||
(let ((position (event-end event))) |
||||
(if (not (windowp (posn-window position))) |
||||
(error "Position not in text area of window")) |
||||
(select-window (posn-window position)) |
||||
(let ((pt (posn-point position))) |
||||
(if (numberp pt) |
||||
;; is there a fake cursor with the actual *point* right where we are? |
||||
(let ((existing (mc/fake-cursor-at-point pt))) |
||||
(if existing |
||||
(mc/remove-fake-cursor existing) |
||||
(save-excursion |
||||
(goto-char pt) |
||||
(mc/create-fake-cursor-at-point)))))) |
||||
(mc/maybe-multiple-cursors-mode))) |
||||
|
||||
;;;###autoload |
||||
(defalias 'mc/add-cursor-on-click 'mc/toggle-cursor-on-click) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-sgml-tag-pair () |
||||
"Mark the tag we're in and its pair for renaming." |
||||
(interactive) |
||||
(when (not (mc--inside-tag-p)) |
||||
(error "Place point inside tag to rename.")) |
||||
(let ((context (mc--get-nice-sgml-context))) |
||||
(if (looking-at "</") |
||||
(setq context (car (last (sgml-get-context))))) |
||||
(goto-char (aref context 2)) |
||||
(let* ((tag-name (aref context 4)) |
||||
(num-chars (length tag-name)) |
||||
(master-start (1+ (point))) |
||||
(mirror-end (save-excursion |
||||
(sgml-skip-tag-forward 1) |
||||
(1- (point))))) |
||||
(goto-char (- mirror-end num-chars)) |
||||
(set-mark mirror-end) |
||||
(mc/create-fake-cursor-at-point) |
||||
(goto-char master-start) |
||||
(set-mark (+ (point) num-chars)))) |
||||
(mc/maybe-multiple-cursors-mode)) |
||||
|
||||
(defun mc--inside-tag-p () |
||||
(save-excursion |
||||
(not (null (sgml-get-context))))) |
||||
|
||||
(provide 'mc-mark-more) |
||||
|
||||
;;; mc-mark-more.el ends here |
Binary file not shown.
@ -1,22 +0,0 @@
@@ -1,22 +0,0 @@
|
||||
;;; mc-mark-pop.el --- Pop cursors off of the mark stack |
||||
|
||||
(require 'multiple-cursors-core) |
||||
|
||||
;;;###autoload |
||||
(defun mc/mark-pop () |
||||
"Add a cursor at the current point, pop off mark ring and jump |
||||
to the popped mark." |
||||
(interactive) |
||||
;; If the mark happens to be at the current point, just pop that one off. |
||||
(while (eql (mark) (point)) |
||||
(pop-mark)) |
||||
(mc/create-fake-cursor-at-point) |
||||
(exchange-point-and-mark) |
||||
(pop-mark) |
||||
(mc/maybe-multiple-cursors-mode)) |
||||
|
||||
;; A good key binding for this feature is perhaps "C-S-p" ('p' for pop). |
||||
|
||||
(provide 'mc-mark-pop) |
||||
|
||||
;;; mc-mark-pop.el ends here |
Binary file not shown.
@ -1,150 +0,0 @@
@@ -1,150 +0,0 @@
|
||||
;;; mc-separate-operations.el - functions that work differently on each cursor |
||||
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen |
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com> |
||||
;; Keywords: editing cursors |
||||
|
||||
;; This program is free software; you can redistribute it and/or modify |
||||
;; it under the terms of the GNU General Public License as published by |
||||
;; the Free Software Foundation, either version 3 of the License, or |
||||
;; (at your option) any later version. |
||||
|
||||
;; This program is distributed in the hope that it will be useful, |
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
;; GNU General Public License for more details. |
||||
|
||||
;; You should have received a copy of the GNU General Public License |
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
;;; Commentary: |
||||
|
||||
;; This file contains functions that work differently on each cursor, |
||||
;; instead of treating all of them the same. |
||||
|
||||
;; Please see multiple-cursors.el for more commentary. |
||||
|
||||
;;; Code: |
||||
|
||||
(require 'multiple-cursors-core) |
||||
|
||||
(defcustom mc/insert-numbers-default 0 |
||||
"The default number at which to start counting for |
||||
`mc/insert-numbers'" |
||||
:type 'integer |
||||
:group 'multiple-cursors) |
||||
|
||||
(defvar mc--insert-numbers-number 0) |
||||
|
||||
;;;###autoload |
||||
(defun mc/insert-numbers (arg) |
||||
"Insert increasing numbers for each cursor, starting at |
||||
`mc/insert-numbers-default' or ARG." |
||||
(interactive "P") |
||||
(setq mc--insert-numbers-number (or (and arg (prefix-numeric-value arg)) |
||||
mc/insert-numbers-default)) |
||||
(mc/for-each-cursor-ordered |
||||
(mc/execute-command-for-fake-cursor 'mc--insert-number-and-increase cursor))) |
||||
|
||||
(defun mc--insert-number-and-increase () |
||||
(interactive) |
||||
(insert (number-to-string mc--insert-numbers-number)) |
||||
(setq mc--insert-numbers-number (1+ mc--insert-numbers-number))) |
||||
|
||||
(defun mc--ordered-region-strings () |
||||
(let (strings) |
||||
(save-excursion |
||||
(mc/for-each-cursor-ordered |
||||
(setq strings (cons (buffer-substring-no-properties |
||||
(mc/cursor-beg cursor) |
||||
(mc/cursor-end cursor)) strings)))) |
||||
(nreverse strings))) |
||||
|
||||
(defvar mc--insert-letters-number 0) |
||||
|
||||
;;;###autoload |
||||
(defun mc/insert-letters (arg) |
||||
"Insert increasing letters for each cursor, starting at 0 or ARG. |
||||
Where letter[0]=a letter[2]=c letter[26]=aa" |
||||
(interactive "P") |
||||
(setq mc--insert-letters-number (or (and arg (prefix-numeric-value arg)) |
||||
0)) |
||||
(mc/for-each-cursor-ordered |
||||
(mc/execute-command-for-fake-cursor 'mc--insert-letter-and-increase cursor))) |
||||
|
||||
(defun mc--number-to-letters (number) |
||||
(let ((letter |
||||
(char-to-string |
||||
(+ (mod number 26) ?a))) |
||||
(number2 (/ number 26))) |
||||
(if (> number2 0) |
||||
(concat (mc--number-to-letters (- number2 1)) letter) |
||||
letter))) |
||||
|
||||
(defun mc--insert-letter-and-increase () |
||||
(interactive) |
||||
(insert (mc--number-to-letters mc--insert-letters-number)) |
||||
(setq mc--insert-letters-number (1+ mc--insert-letters-number))) |
||||
|
||||
(defvar mc--strings-to-replace nil) |
||||
|
||||
(defun mc--replace-region-strings-1 () |
||||
(interactive) |
||||
(delete-region (region-beginning) (region-end)) |
||||
(save-excursion (insert (car mc--strings-to-replace))) |
||||
(setq mc--strings-to-replace (cdr mc--strings-to-replace))) |
||||
|
||||
(defun mc--replace-region-strings () |
||||
(mc/for-each-cursor-ordered |
||||
(mc/execute-command-for-fake-cursor 'mc--replace-region-strings-1 cursor))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/reverse-regions () |
||||
(interactive) |
||||
(if (not multiple-cursors-mode) |
||||
(progn |
||||
(mc/mark-next-lines 1) |
||||
(mc/reverse-regions) |
||||
(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))) |
||||
(mc--replace-region-strings))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/sort-regions () |
||||
(interactive) |
||||
(unless (use-region-p) |
||||
(mc/execute-command-for-all-cursors 'mark-sexp)) |
||||
(setq mc--strings-to-replace (sort (mc--ordered-region-strings) 'string<)) |
||||
(mc--replace-region-strings)) |
||||
|
||||
|
||||
;;;###autoload |
||||
(defun mc/vertical-align (character) |
||||
"Aligns all cursors vertically with a given CHARACTER to the one with the |
||||
highest column number (the rightest). |
||||
Might not behave as intended if more than one cursors are on the same line." |
||||
(interactive "c") |
||||
(let ((rightest-column (current-column))) |
||||
(mc/execute-command-for-all-cursors |
||||
(lambda () "get the rightest cursor" |
||||
(interactive) |
||||
(setq rightest-column (max (current-column) rightest-column)) |
||||
)) |
||||
(mc/execute-command-for-all-cursors |
||||
(lambda () |
||||
(interactive) |
||||
(let ((missing-spaces (- rightest-column (current-column)))) |
||||
(save-excursion (insert (make-string missing-spaces character))) |
||||
(forward-char missing-spaces)))))) |
||||
|
||||
;;;###autoload |
||||
(defun mc/vertical-align-with-space () |
||||
"Aligns all cursors with whitespace like `mc/vertical-align' does" |
||||
(interactive) |
||||
(mc/vertical-align 32)) |
||||
|
||||
(provide 'mc-separate-operations) |
||||
;;; mc-separate-operations.el ends here |
Binary file not shown.
@ -1,852 +0,0 @@
@@ -1,852 +0,0 @@
|
||||
;;; multiple-cursors-core.el --- An experiment in multiple cursors for emacs. |
||||
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen |
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com> |
||||
;; Keywords: editing cursors |
||||
|
||||
;; This program is free software; you can redistribute it and/or modify |
||||
;; it under the terms of the GNU General Public License as published by |
||||
;; the Free Software Foundation, either version 3 of the License, or |
||||
;; (at your option) any later version. |
||||
|
||||
;; This program is distributed in the hope that it will be useful, |
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
;; GNU General Public License for more details. |
||||
|
||||
;; You should have received a copy of the GNU General Public License |
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
;;; Commentary: |
||||
|
||||
;; This file contains the core functionality of multiple-cursors. |
||||
;; Please see multiple-cursors.el for more commentary. |
||||
|
||||
;;; Code: |
||||
|
||||
(require 'cl-lib) |
||||
(require 'rect) |
||||
|
||||
(defvar mc--read-char) |
||||
|
||||
(defface mc/cursor-face |
||||
'((t (:inverse-video t))) |
||||
"The face used for fake cursors" |
||||
:group 'multiple-cursors) |
||||
|
||||
(defface mc/cursor-bar-face |
||||
`((t (:height 1 :background ,(face-attribute 'cursor :background)))) |
||||
"The face used for fake cursors if the cursor-type is bar" |
||||
:group 'multiple-cursors) |
||||
|
||||
(defface mc/region-face |
||||
'((t :inherit region)) |
||||
"The face used for fake regions" |
||||
:group 'multiple-cursors) |
||||
|
||||
(defmacro mc/add-fake-cursor-to-undo-list (&rest forms) |
||||
"Make sure point is in the right place when undoing" |
||||
(let ((uc (make-symbol "undo-cleaner"))) |
||||
`(let ((,uc (cons 'apply (cons 'deactivate-cursor-after-undo (list id))))) |
||||
(setq buffer-undo-list (cons ,uc buffer-undo-list)) |
||||
,@forms |
||||
(if (eq ,uc (car buffer-undo-list)) ;; if nothing has been added to the undo-list |
||||
(setq buffer-undo-list (cdr buffer-undo-list)) ;; then pop the cleaner right off again |
||||
(setq buffer-undo-list ;; otherwise add a function to activate this cursor |
||||
(cons (cons 'apply (cons 'activate-cursor-for-undo (list id))) buffer-undo-list)))))) |
||||
|
||||
(defun mc/all-fake-cursors (&optional start end) |
||||
(cl-remove-if-not 'mc/fake-cursor-p |
||||
(overlays-in (or start (point-min)) |
||||
(or end (point-max))))) |
||||
|
||||
(defmacro mc/for-each-fake-cursor (&rest forms) |
||||
"Runs the body for each fake cursor, bound to the name cursor" |
||||
`(mapc #'(lambda (cursor) ,@forms) |
||||
(mc/all-fake-cursors))) |
||||
|
||||
(defmacro mc/save-excursion (&rest forms) |
||||
"Saves and restores all the state that multiple-cursors cares about." |
||||
(let ((cs (make-symbol "current-state"))) |
||||
`(let ((,cs (mc/store-current-state-in-overlay |
||||
(make-overlay (point) (point) nil nil t)))) |
||||
(overlay-put ,cs 'type 'original-cursor) |
||||
(save-excursion ,@forms) |
||||
(mc/pop-state-from-overlay ,cs)))) |
||||
|
||||
(defun mc--compare-by-overlay-start (o1 o2) |
||||
(< (overlay-start o1) (overlay-start o2))) |
||||
|
||||
(defmacro mc/for-each-cursor-ordered (&rest forms) |
||||
"Runs the body for each cursor, fake and real, bound to the name cursor" |
||||
(let ((rci (make-symbol "real-cursor-id"))) |
||||
`(let ((,rci (overlay-get (mc/create-fake-cursor-at-point) 'mc-id))) |
||||
(mapc #'(lambda (cursor) |
||||
(when (mc/fake-cursor-p cursor) |
||||
,@forms)) |
||||
(sort (overlays-in (point-min) (point-max)) 'mc--compare-by-overlay-start)) |
||||
(mc/pop-state-from-overlay (mc/cursor-with-id ,rci))))) |
||||
|
||||
(defmacro mc/save-window-scroll (&rest forms) |
||||
"Saves and restores the window scroll position" |
||||
(let ((p (make-symbol "p")) |
||||
(s (make-symbol "start")) |
||||
(h (make-symbol "hscroll"))) |
||||
`(let ((,p (set-marker (make-marker) (point))) |
||||
(,s (set-marker (make-marker) (window-start))) |
||||
(,h (window-hscroll))) |
||||
,@forms |
||||
(goto-char ,p) |
||||
(set-window-start nil ,s t) |
||||
(set-window-hscroll nil ,h) |
||||
(set-marker ,p nil) |
||||
(set-marker ,s nil)))) |
||||
|
||||
(defun mc/cursor-is-bar () |
||||
"Return non-nil if the cursor is a bar." |
||||
(or (eq cursor-type 'bar) |
||||
(and (listp cursor-type) |
||||
(eq (car cursor-type) 'bar)))) |
||||
|
||||
(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) |
||||
"Create overlay to look like cursor at end of line." |
||||
(let ((overlay (make-overlay pos pos nil nil nil))) |
||||
(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)) |
||||
|
||||
(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 (mc/cursor-is-bar) |
||||
(overlay-put overlay 'before-string (propertize "|" 'face 'mc/cursor-bar-face)) |
||||
(overlay-put overlay 'face 'mc/cursor-face)) |
||||
overlay)) |
||||
|
||||
(defun mc/make-cursor-overlay-at-point () |
||||
"Create overlay to look like cursor. |
||||
Special case for end of line, because overlay over a newline |
||||
highlights the entire width of the window." |
||||
(if (eolp) |
||||
(mc/make-cursor-overlay-at-eol (point)) |
||||
(mc/make-cursor-overlay-inline (point)))) |
||||
|
||||
(defun mc/make-region-overlay-between-point-and-mark () |
||||
"Create overlay to look like active region." |
||||
(let ((overlay (make-overlay (mark) (point) nil nil t))) |
||||
(overlay-put overlay 'face 'mc/region-face) |
||||
(overlay-put overlay 'type 'additional-region) |
||||
overlay)) |
||||
|
||||
(defvar mc/cursor-specific-vars '(transient-mark-mode |
||||
kill-ring |
||||
kill-ring-yank-pointer |
||||
mark-ring |
||||
mark-active |
||||
yank-undo-function |
||||
autopair-action |
||||
autopair-wrap-action |
||||
temporary-goal-column |
||||
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.") |
||||
|
||||
(defun mc/store-current-state-in-overlay (o) |
||||
"Store relevant info about point and mark in the given overlay." |
||||
(overlay-put o 'point (set-marker (make-marker) (point))) |
||||
(overlay-put o 'mark (set-marker (make-marker) |
||||
(let ((mark-even-if-inactive t)) |
||||
(mark)))) |
||||
(dolist (var mc/cursor-specific-vars) |
||||
(when (boundp var) (overlay-put o var (symbol-value var)))) |
||||
o) |
||||
|
||||
(defun mc/restore-state-from-overlay (o) |
||||
"Restore point and mark from stored info in the given overlay." |
||||
(goto-char (overlay-get o 'point)) |
||||
(set-marker (mark-marker) (overlay-get o 'mark)) |
||||
(dolist (var mc/cursor-specific-vars) |
||||
(when (boundp var) (set var (overlay-get o var))))) |
||||
|
||||
(defun mc/remove-fake-cursor (o) |
||||
"Delete overlay with state, including dependent overlays and markers." |
||||
(set-marker (overlay-get o 'point) nil) |
||||
(set-marker (overlay-get o 'mark) nil) |
||||
(mc/delete-region-overlay o) |
||||
(delete-overlay o)) |
||||
|
||||
(defun mc/pop-state-from-overlay (o) |
||||
"Restore the state stored in given overlay and then remove the overlay." |
||||
(mc/restore-state-from-overlay o) |
||||
(mc/remove-fake-cursor o)) |
||||
|
||||
(defun mc/delete-region-overlay (o) |
||||
"Remove the dependent region overlay for a given cursor overlay." |
||||
(ignore-errors |
||||
(delete-overlay (overlay-get o 'region-overlay)))) |
||||
|
||||
(defvar mc--current-cursor-id 0 |
||||
"Var to store increasing id of fake cursors, used to keep track of them for undo.") |
||||
|
||||
(defun mc/create-cursor-id () |
||||
"Returns a unique cursor id" |
||||
(cl-incf mc--current-cursor-id)) |
||||
|
||||
(defvar mc--max-cursors-original nil |
||||
"This variable maintains the original maximum number of cursors. |
||||
When `mc/create-fake-cursor-at-point' is called and |
||||
`mc/max-cursors' is overridden, this value serves as a backup so |
||||
that `mc/max-cursors' can take on a new value. When |
||||
`mc/remove-fake-cursors' is called, the values are reset.") |
||||
|
||||
(defcustom mc/max-cursors nil |
||||
"Safety ceiling for the number of active cursors. |
||||
If your emacs slows down or freezes when using too many cursors, |
||||
customize this value appropriately. |
||||
|
||||
Cursors will be added until this value is reached, at which point |
||||
you can either temporarily override the value or abort the |
||||
operation entirely. |
||||
|
||||
If this value is nil, there is no ceiling." |
||||
:type '(integer) |
||||
: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." |
||||
(unless mc--max-cursors-original |
||||
(setq mc--max-cursors-original mc/max-cursors)) |
||||
(when mc/max-cursors |
||||
(unless (< (mc/num-cursors) mc/max-cursors) |
||||
(if (yes-or-no-p (format "%d active cursors. Continue? " (mc/num-cursors))) |
||||
(setq mc/max-cursors (read-number "Enter a new, temporary maximum: ")) |
||||
(mc/remove-fake-cursors) |
||||
(error "Aborted: too many cursors")))) |
||||
(let ((overlay (mc/make-cursor-overlay-at-point))) |
||||
(overlay-put overlay 'mc-id (or id (mc/create-cursor-id))) |
||||
(overlay-put overlay 'type 'fake-cursor) |
||||
(overlay-put overlay 'priority 100) |
||||
(mc/store-current-state-in-overlay overlay) |
||||
(when (use-region-p) |
||||
(overlay-put overlay 'region-overlay |
||||
(mc/make-region-overlay-between-point-and-mark))) |
||||
overlay)) |
||||
|
||||
(defun mc/execute-command (cmd) |
||||
"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) |
||||
(call-interactively cmd)) |
||||
(run-hooks 'post-command-hook) |
||||
(when deactivate-mark (deactivate-mark))) |
||||
|
||||
(defvar mc--executing-command-for-fake-cursor nil) |
||||
|
||||
(defun mc/execute-command-for-fake-cursor (cmd cursor) |
||||
(let ((mc--executing-command-for-fake-cursor t) |
||||
(id (overlay-get cursor 'mc-id)) |
||||
(annoying-arrows-mode nil) |
||||
(smooth-scroll-margin 0)) |
||||
(mc/add-fake-cursor-to-undo-list |
||||
(mc/pop-state-from-overlay cursor) |
||||
(ignore-errors |
||||
(mc/execute-command cmd) |
||||
(mc/create-fake-cursor-at-point id))))) |
||||
|
||||
(defun mc/execute-command-for-all-fake-cursors (cmd) |
||||
"Calls CMD interactively for each cursor. |
||||
It works by moving point to the fake cursor, setting |
||||
up the proper environment, and then removing the cursor. |
||||
After executing the command, it sets up a new fake |
||||
cursor with updated info." |
||||
(mc/save-excursion |
||||
(mc/save-window-scroll |
||||
(mc/for-each-fake-cursor |
||||
(save-excursion |
||||
(mc/execute-command-for-fake-cursor cmd cursor))))) |
||||
(mc--reset-read-prompts)) |
||||
|
||||
(defun mc/execute-command-for-all-cursors (cmd) |
||||
"Calls CMD interactively for the real cursor and all fakes." |
||||
(call-interactively cmd) |
||||
(mc/execute-command-for-all-fake-cursors cmd)) |
||||
|
||||
;; Intercept some reading commands so you won't have to |
||||
;; answer them for every single cursor |
||||
|
||||
(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--read-char nil) |
||||
(setq mc--read-quoted-char nil)) |
||||
|
||||
(mc--reset-read-prompts) |
||||
|
||||
(defun mc/fake-cursor-p (o) |
||||
"Predicate to check if an overlay is a fake cursor" |
||||
(eq (overlay-get o 'type) 'fake-cursor)) |
||||
|
||||
(defun mc/cursor-with-id (id) |
||||
"Find the first cursor with the given id, or nil" |
||||
(cl-find-if #'(lambda (o) (and (mc/fake-cursor-p o) |
||||
(= id (overlay-get o 'mc-id)))) |
||||
(overlays-in (point-min) (point-max)))) |
||||
|
||||
(defvar mc--stored-state-for-undo nil |
||||
"Variable to keep the state of the real cursor while undoing a fake one") |
||||
|
||||
(defun activate-cursor-for-undo (id) |
||||
"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 |
||||
(make-overlay (point) (point) nil nil t))) |
||||
(mc/pop-state-from-overlay cursor)))) |
||||
|
||||
(defun deactivate-cursor-after-undo (id) |
||||
"Called when undoing to reinstate the real cursor after undoing a fake one." |
||||
(when mc--stored-state-for-undo |
||||
(mc/create-fake-cursor-at-point id) |
||||
(mc/pop-state-from-overlay mc--stored-state-for-undo) |
||||
(setq mc--stored-state-for-undo nil))) |
||||
|
||||
(defcustom mc/always-run-for-all nil |
||||
"Disables whitelisting and always executes commands for every fake cursor." |
||||
:type '(boolean) |
||||
:group 'multiple-cursors) |
||||
|
||||
(defcustom mc/always-repeat-command nil |
||||
"Disables confirmation for `mc/repeat-command' command." |
||||
: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.") |
||||
|
||||
(defvar mc--default-cmds-to-run-once nil |
||||
"Default set of commands to run only once in multiple-cursors-mode.") |
||||
|
||||
(setq mc--default-cmds-to-run-once '(mc/edit-lines |
||||
mc/edit-ends-of-lines |
||||
mc/edit-beginnings-of-lines |
||||
mc/mark-next-like-this |
||||
mc/mark-next-like-this-word |
||||
mc/mark-next-like-this-symbol |
||||
mc/mark-next-word-like-this |
||||
mc/mark-next-symbol-like-this |
||||
mc/mark-previous-like-this |
||||
mc/mark-previous-like-this-word |
||||
mc/mark-previous-like-this-symbol |
||||
mc/mark-previous-word-like-this |
||||
mc/mark-previous-symbol-like-this |
||||
mc/mark-all-like-this |
||||
mc/mark-all-words-like-this |
||||
mc/mark-all-symbols-like-this |
||||
mc/mark-more-like-this-extended |
||||
mc/mark-all-like-this-in-defun |
||||
mc/mark-all-words-like-this-in-defun |
||||
mc/mark-all-symbols-like-this-in-defun |
||||
mc/mark-all-like-this-dwim |
||||
mc/mark-all-dwim |
||||
mc/mark-sgml-tag-pair |
||||
mc/insert-numbers |
||||
mc/insert-letters |
||||
mc/sort-regions |
||||
mc/reverse-regions |
||||
mc/cycle-forward |
||||
mc/cycle-backward |
||||
mc/add-cursor-on-click |
||||
mc/mark-pop |
||||
mc/add-cursors-to-all-matches |
||||
mc/mmlte--left |
||||
mc/mmlte--right |
||||
mc/mmlte--up |
||||
mc/mmlte--down |
||||
mc/unmark-next-like-this |
||||
mc/unmark-previous-like-this |
||||
mc/skip-to-next-like-this |
||||
mc/skip-to-previous-like-this |
||||
rrm/switch-to-multiple-cursors |
||||
mc-hide-unmatched-lines-mode |
||||
mc/repeat-command |
||||
hum/keyboard-quit |
||||
hum/unhide-invisible-overlays |
||||
save-buffer |
||||
ido-exit-minibuffer |
||||
ivy-done |
||||
exit-minibuffer |
||||
minibuffer-complete-and-exit |
||||
execute-extended-command |
||||
eval-expression |
||||
undo |
||||
redo |
||||
undo-tree-undo |
||||
undo-tree-redo |
||||
universal-argument |
||||
universal-argument-more |
||||
universal-argument-other-key |
||||
negative-argument |
||||
digit-argument |
||||
top-level |
||||
recenter-top-bottom |
||||
describe-mode |
||||
describe-key-1 |
||||
describe-function |
||||
describe-bindings |
||||
describe-prefix-bindings |
||||
view-echo-area-messages |
||||
other-window |
||||
kill-buffer-and-window |
||||
split-window-right |
||||
split-window-below |
||||
delete-other-windows |
||||
toggle-window-split |
||||
mwheel-scroll |
||||
scroll-up-command |
||||
scroll-down-command |
||||
mouse-set-point |
||||
mouse-drag-region |
||||
quit-window |
||||
toggle-read-only |
||||
windmove-left |
||||
windmove-right |
||||
windmove-up |
||||
windmove-down |
||||
repeat-complex-command)) |
||||
|
||||
(defvar mc--default-cmds-to-run-for-all nil |
||||
"Default set of commands that should be mirrored by all cursors") |
||||
|
||||
(setq mc--default-cmds-to-run-for-all '(mc/keyboard-quit |
||||
self-insert-command |
||||
quoted-insert |
||||
previous-line |
||||
next-line |
||||
newline |
||||
newline-and-indent |
||||
open-line |
||||
delete-blank-lines |
||||
transpose-chars |
||||
transpose-lines |
||||
transpose-paragraphs |
||||
transpose-regions |
||||
join-line |
||||
right-char |
||||
right-word |
||||
forward-char |
||||
forward-word |
||||
left-char |
||||
left-word |
||||
backward-char |
||||
backward-word |
||||
forward-paragraph |
||||
backward-paragraph |
||||
upcase-word |
||||
downcase-word |
||||
capitalize-word |
||||
forward-list |
||||
backward-list |
||||
hippie-expand |
||||
hippie-expand-lines |
||||
yank |
||||
yank-pop |
||||
append-next-kill |
||||
kill-word |
||||
kill-line |
||||
kill-whole-line |
||||
backward-kill-word |
||||
backward-delete-char-untabify |
||||
delete-char delete-forward-char |
||||
delete-backward-char |
||||
py-electric-backspace |
||||
c-electric-backspace |
||||
org-delete-backward-char |
||||
cperl-electric-backspace |
||||
python-indent-dedent-line-backspace |
||||
paredit-backward-delete |
||||
autopair-backspace |
||||
just-one-space |
||||
zap-to-char |
||||
end-of-line |
||||
set-mark-command |
||||
exchange-point-and-mark |
||||
cua-set-mark |
||||
cua-replace-region |
||||
cua-delete-region |
||||
move-end-of-line |
||||
beginning-of-line |
||||
move-beginning-of-line |
||||
kill-ring-save |
||||
back-to-indentation |
||||
subword-forward |
||||
subword-backward |
||||
subword-mark |
||||
subword-kill |
||||
subword-backward-kill |
||||
subword-transpose |
||||
subword-capitalize |
||||
subword-upcase |
||||
subword-downcase |
||||
er/expand-region |
||||
er/contract-region |
||||
smart-forward |
||||
smart-backward |
||||
smart-up |
||||
smart-down)) |
||||
|
||||
(defvar mc/cmds-to-run-for-all nil |
||||
"Commands to run for all cursors in multiple-cursors-mode") |
||||
|
||||
(provide 'multiple-cursors-core) |
||||
|
||||
;; Local Variables: |
||||
;; coding: utf-8 |
||||
;; End: |
||||
|
||||
;;; multiple-cursors-core.el ends here |
Binary file not shown.
@ -1,6 +0,0 @@
@@ -1,6 +0,0 @@
|
||||
(define-package "multiple-cursors" "20191210.1759" "Multiple cursors for Emacs." |
||||
'((cl-lib "0.5")) |
||||
:commit "b880554d04b8f61165afba7d4de19ac9e39bb7ab") |
||||
;; Local Variables: |
||||
;; no-byte-compile: t |
||||
;; End: |
@ -1,203 +0,0 @@
@@ -1,203 +0,0 @@
|
||||
;;; multiple-cursors.el --- Multiple cursors for emacs. |
||||
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen |
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com> |
||||
;; Version: 1.4.0 |
||||
;; Keywords: editing cursors |
||||
|
||||
;; This program is free software; you can redistribute it and/or modify |
||||
;; it under the terms of the GNU General Public License as published by |
||||
;; the Free Software Foundation, either version 3 of the License, or |
||||
;; (at your option) any later version. |
||||
|
||||
;; This program is distributed in the hope that it will be useful, |
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
;; GNU General Public License for more details. |
||||
|
||||
;; You should have received a copy of the GNU General Public License |
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
;;; Commentary: |
||||
|
||||
;; 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 |
||||
;; great success and much merriment. |
||||
|
||||
;; ## Basic usage |
||||
|
||||
;; Start out with: |
||||
|
||||
;; (require 'multiple-cursors) |
||||
|
||||
;; Then you have to set up your keybindings - multiple-cursors doesn't presume to |
||||
;; know how you'd like them laid out. Here are some examples: |
||||
|
||||
;; When you have an active region that spans multiple lines, the following will |
||||
;; add a cursor to each line: |
||||
|
||||
;; (global-set-key (kbd "C-S-c C-S-c") 'mc/edit-lines) |
||||
|
||||
;; When you want to add multiple cursors not based on continuous lines, but based on |
||||
;; keywords in the buffer, use: |
||||
|
||||
;; (global-set-key (kbd "C->") 'mc/mark-next-like-this) |
||||
;; (global-set-key (kbd "C-<") 'mc/mark-previous-like-this) |
||||
;; (global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this) |
||||
|
||||
;; First mark the word, then add more cursors. |
||||
|
||||
;; To get out of multiple-cursors-mode, press `<return>` or `C-g`. The latter will |
||||
;; first disable multiple regions before disabling multiple cursors. If you want to |
||||
;; insert a newline in multiple-cursors-mode, use `C-j`. |
||||
|
||||
;; ## Video |
||||
|
||||
;; You can [watch an intro to multiple-cursors at Emacs Rocks](http://emacsrocks.com/e13.html). |
||||
|
||||
;; ## Command overview |
||||
|
||||
;; ### Mark one more occurrence |
||||
|
||||
;; - `mc/mark-next-like-this`: Adds a cursor and region at the next part of the buffer forwards that matches the current region. |
||||
;; - `mc/mark-next-like-this-word`: Adds a cursor and region at the next part of the buffer forwards that matches the current region, if no region is selected it selects the word at the point. |
||||
;; - `mc/mark-next-like-this-symbol`: Adds a cursor and region at the next part of the buffer forwards that matches the current region, if no region is selected it selects the symbol at the point. |
||||
;; - `mc/mark-next-word-like-this`: Like `mc/mark-next-like-this` but only for whole words. |
||||
;; - `mc/mark-next-symbol-like-this`: Like `mc/mark-next-like-this` but only for whole symbols. |
||||
;; - `mc/mark-previous-like-this`: Adds a cursor and region at the next part of the buffer backwards that matches the current region. |
||||
;; - `mc/mark-previous-word-like-this`: Like `mc/mark-previous-like-this` but only for whole words. |
||||
;; - `mc/mark-previous-symbol-like-this`: Like `mc/mark-previous-like-this` but only for whole symbols. |
||||
;; - `mc/mark-more-like-this-extended`: Use arrow keys to quickly mark/skip next/previous occurrences. |
||||
;; - `mc/add-cursor-on-click`: Bind to a mouse event to add cursors by clicking. See tips-section. |
||||
|
||||
;; ### Mark many occurrences |
||||
|
||||
;; - `mc/mark-all-like-this`: Marks all parts of the buffer that matches the current region. |
||||
;; - `mc/mark-all-words-like-this`: Like `mc/mark-all-like-this` but only for whole words. |
||||
;; - `mc/mark-all-symbols-like-this`: Like `mc/mark-all-like-this` but only for whole symbols. |
||||
;; - `mc/mark-all-in-region`: Prompts for a string to match in the region, adding cursors to all of them. |
||||
;; - `mc/mark-all-like-this-in-defun`: Marks all parts of the current defun that matches the current region. |
||||
;; - `mc/mark-all-words-like-this-in-defun`: Like `mc/mark-all-like-this-in-defun` but only for whole words. |
||||
;; - `mc/mark-all-symbols-like-this-in-defun`: Like `mc/mark-all-like-this-in-defun` but only for whole symbols. |
||||
;; - `mc/mark-all-like-this-dwim`: Tries to be smart about marking everything you want. Can be pressed multiple times. |
||||
|
||||
;; ### Special |
||||
|
||||
;; - `set-rectangular-region-anchor`: Think of this one as `set-mark` except you're marking a rectangular region. |
||||
;; - `mc/mark-sgml-tag-pair`: Mark the current opening and closing tag. |
||||
;; - `mc/insert-numbers`: Insert increasing numbers for each cursor, top to bottom. |
||||
;; - `mc/insert-letters`: Insert increasing letters for each cursor, top to bottom. |
||||
;; - `mc/sort-regions`: Sort the marked regions alphabetically. |
||||
;; - `mc/reverse-regions`: Reverse the order of the marked regions. |
||||
|
||||
;; ## Tips and tricks |
||||
|
||||
;; - To get out of multiple-cursors-mode, press `<return>` or `C-g`. The latter will |
||||
;; first disable multiple regions before disabling multiple cursors. If you want to |
||||
;; insert a newline in multiple-cursors-mode, use `C-j`. |
||||
;; |
||||
;; - Sometimes you end up with cursors outside of your view. You can |
||||
;; scroll the screen to center on each cursor with `C-v` and `M-v`. |
||||
;; |
||||
;; - Try pressing `mc/mark-next-like-this` with no region selected. It will just add a cursor |
||||
;; on the next line. |
||||
;; |
||||
;; - Try pressing `mc/mark-next-like-this-word` or |
||||
;; `mc/mark-next-like-this-symbol` with no region selected. It will |
||||
;; mark the symbol and add a cursor at the next occurrence |
||||
;; |
||||
;; - Try pressing `mc/mark-all-like-this-dwim` on a tagname in html-mode. |
||||
;; |
||||
;; - Notice that the number of cursors active can be seen in the modeline. |
||||
;; |
||||
;; - If you get out of multiple-cursors-mode and yank - it will yank only |
||||
;; from the kill-ring of main cursor. To yank from the kill-rings of |
||||
;; every cursor use yank-rectangle, normally found at C-x r y. |
||||
;; |
||||
;; - You can use `mc/reverse-regions` with nothing selected and just one cursor. |
||||
;; It will then flip the sexp at point and the one below it. |
||||
;; |
||||
;; - If you would like to keep the global bindings clean, and get custom keybindings |
||||
;; when the region is active, you can try [region-bindings-mode](https://github.com/fgallina/region-bindings-mode). |
||||
;; |
||||
;; BTW, I highly recommend adding `mc/mark-next-like-this` to a key binding that's |
||||
;; right next to the key for `er/expand-region`. |
||||
|
||||
;; ### Binding mouse events |
||||
|
||||
;; To override a mouse event, you will likely have to also unbind the |
||||
;; `down-mouse` part of the event. Like this: |
||||
;; |
||||
;; (global-unset-key (kbd "M-<down-mouse-1>")) |
||||
;; (global-set-key (kbd "M-<mouse-1>") 'mc/add-cursor-on-click) |
||||
;; |
||||
;; Or you can do like me and find an unused, but less convenient, binding: |
||||
;; |
||||
;; (global-set-key (kbd "C-S-<mouse-1>") 'mc/add-cursor-on-click) |
||||
|
||||
;; ## Unknown commands |
||||
|
||||
;; Multiple-cursors uses two lists of commands to know what to do: the run-once list |
||||
;; and the run-for-all list. It comes with a set of defaults, but it would be beyond silly |
||||
;; to try and include all the known Emacs commands. |
||||
|
||||
;; So that's why multiple-cursors occasionally asks what to do about a command. It will |
||||
;; then remember your choice by saving it in `~/.emacs.d/.mc-lists.el`. You can change |
||||
;; the location with: |
||||
|
||||
;; (setq mc/list-file "/my/preferred/file") |
||||
|
||||
;; ## Known limitations |
||||
|
||||
;; * isearch-forward and isearch-backward aren't supported with multiple cursors. |
||||
;; You should feel free to add a simplified version that can work with it. |
||||
;; * Commands run with `M-x` won't be repeated for all cursors. |
||||
;; * All key bindings that refer to lambdas are always run for all cursors. If you |
||||
;; need to limit it, you will have to give it a name. |
||||
;; * Redo might screw with your cursors. Undo works very well. |
||||
|
||||
;; ## Contribute |
||||
|
||||
;; Yes, please do. There's a suite of tests, so remember to add tests for your |
||||
;; specific feature, or I might break it later. |
||||
|
||||
;; You'll find the repo at: |
||||
|
||||
;; https://github.com/magnars/multiple-cursors.el |
||||
|
||||
;; To fetch the test dependencies: |
||||
|
||||
;; $ cd /path/to/multiple-cursors |
||||
;; $ git submodule update --init |
||||
|
||||
;; Run the tests with: |
||||
|
||||
;; $ ./util/ecukes/ecukes --graphical |
||||
|
||||
;; ## Contributors |
||||
|
||||
;; * [Takafumi Arakaki](https://github.com/tkf) made .mc-lists.el diff friendly |
||||
;; * [Marco Baringer](https://github.com/segv) contributed looping to mc/cycle and adding cursors without region for mark-more. |
||||
;; * [Ivan Andrus](https://github.com/gvol) added showing number of cursors in mode-line |
||||
;; * [Fuco](https://github.com/Fuco1) added the first version of `mc/mark-all-like-this-dwim` |
||||
|
||||
;; Thanks! |
||||
|
||||
;;; Code: |
||||
|
||||
(defgroup multiple-cursors nil |
||||
"Multiple cursors for emacs." |
||||
:group 'editing) |
||||
|
||||
(require 'mc-edit-lines) |
||||
(require 'mc-cycle-cursors) |
||||
(require 'mc-mark-more) |
||||
(require 'mc-mark-pop) |
||||
(require 'rectangular-region-mode) |
||||
(require 'mc-separate-operations) |
||||
(require 'mc-hide-unmatched-lines-mode) |
||||
|
||||
(provide 'multiple-cursors) |
||||
|
||||
;;; multiple-cursors.el ends here |
Binary file not shown.
@ -1,125 +0,0 @@
@@ -1,125 +0,0 @@
|
||||
;;; rectangular-region-mode.el |
||||
|
||||
;; Copyright (C) 2012-2016 Magnar Sveen |
||||
|
||||
;; Author: Magnar Sveen <magnars@gmail.com> |
||||
;; Keywords: editing cursors |
||||
|
||||
;; This program is free software; you can redistribute it and/or modify |
||||
;; it under the terms of the GNU General Public License as published by |
||||
;; the Free Software Foundation, either version 3 of the License, or |
||||
;; (at your option) any later version. |
||||
|
||||
;; This program is distributed in the hope that it will be useful, |
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
;; GNU General Public License for more details. |
||||
|
||||
;; You should have received a copy of the GNU General Public License |
||||
;; along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
;;; Commentary: |
||||
|
||||
;; (global-set-key (kbd "H-SPC") 'set-rectangular-region-anchor) |
||||
|
||||
;; 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. |
||||
|
||||
;;; Code: |
||||
|
||||
(require 'multiple-cursors-core) |
||||
|
||||
(defvar rrm/anchor (make-marker) |
||||
"The position in the buffer that anchors the rectangular region.") |
||||
|
||||
(defvar rectangular-region-mode-map (make-sparse-keymap) |
||||
"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 "<return>") 'rrm/switch-to-multiple-cursors) |
||||
|
||||
(defvar rectangular-region-mode nil) |
||||
|
||||
(defun rrm/keyboard-quit () |
||||
"Exit rectangular-region-mode." |
||||
(interactive) |
||||
(rectangular-region-mode 0) |
||||
(rrm/remove-rectangular-region-overlays) |
||||
(deactivate-mark)) |
||||
|
||||
;; Bind this to a key (for instance H-SPC) to start rectangular-region-mode |
||||
;;;###autoload |
||||
(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." |
||||
(interactive) |
||||
(set-marker rrm/anchor (point)) |
||||
(push-mark (point)) |
||||
(rectangular-region-mode 1)) |
||||
|
||||
(defun rrm/remove-rectangular-region-overlays () |
||||
"Remove all rectangular-region overlays." |
||||
(mc/remove-fake-cursors) |
||||
(mapc #'(lambda (o) |
||||
(when (eq (overlay-get o 'type) 'additional-region) |
||||
(delete-overlay o))) |
||||
(overlays-in (point-min) (point-max)))) |
||||
|
||||
(defun rrm/repaint () |
||||
"Start from the anchor and draw a rectangle between it and point." |
||||
(if (not rectangular-region-mode) |
||||
(remove-hook 'post-command-hook 'rrm/repaint t) |
||||
;; else |
||||
(rrm/remove-rectangular-region-overlays) |
||||
(let* ((annoying-arrows-mode nil) |
||||
(point-column (current-column)) |
||||
(point-line (mc/line-number-at-pos)) |
||||
(anchor-column (save-excursion (goto-char rrm/anchor) (current-column))) |
||||
(anchor-line (save-excursion (goto-char rrm/anchor) (mc/line-number-at-pos))) |
||||
(left-column (if (< point-column anchor-column) point-column anchor-column)) |
||||
(right-column (if (> point-column anchor-column) point-column anchor-column)) |
||||
(navigation-step (if (< point-line anchor-line) 1 -1))) |
||||
(move-to-column anchor-column) |
||||
(set-mark (point)) |
||||
(move-to-column point-column) |
||||
(mc/save-excursion |
||||
(while (not (= anchor-line (mc/line-number-at-pos))) |
||||
(forward-line navigation-step) |
||||
(move-to-column anchor-column) |
||||
(when (= anchor-column (current-column)) |
||||
(set-mark (point)) |
||||
(move-to-column point-column) |
||||
(when (= point-column (current-column)) |
||||
(mc/create-fake-cursor-at-point)))))))) |
||||
|
||||
(defun rrm/switch-to-multiple-cursors (&rest forms) |
||||
"Switch from rectangular-region-mode to multiple-cursors-mode." |
||||
(interactive) |
||||
(rectangular-region-mode 0) |
||||
(multiple-cursors-mode 1)) |
||||
|
||||
(defadvice er/expand-region (before switch-from-rrm-to-mc activate) |
||||
(when rectangular-region-mode |
||||
(rrm/switch-to-multiple-cursors))) |
||||
|
||||
(defadvice kill-ring-save (before switch-from-rrm-to-mc activate) |
||||
(when rectangular-region-mode |
||||
(rrm/switch-to-multiple-cursors))) |
||||
|
||||
;;;###autoload |
||||
(define-minor-mode rectangular-region-mode |
||||
"A mode for creating a rectangular region to edit" |
||||
nil " rr" rectangular-region-mode-map |
||||
(if rectangular-region-mode |
||||
(progn |
||||
(add-hook 'after-change-functions 'rrm/switch-to-multiple-cursors t t) |
||||
(add-hook 'post-command-hook 'rrm/repaint t t)) |
||||
(remove-hook 'after-change-functions 'rrm/switch-to-multiple-cursors t) |
||||
(remove-hook 'post-command-hook 'rrm/repaint t) |
||||
(set-marker rrm/anchor nil))) |
||||
|
||||
(provide 'rectangular-region-mode) |
||||
|
||||
;;; rectangular-region-mode.el ends here |
Binary file not shown.
Loading…
Reference in new issue