multiple-cursors-core.el (33697B)
1 ;;; multiple-cursors-core.el --- An experiment in multiple cursors for emacs. 2 3 ;; Copyright (C) 2012 Magnar Sveen 4 5 ;; Author: Magnar Sveen <magnars@gmail.com> 6 ;; Keywords: editing cursors 7 8 ;; This program is free software; you can redistribute it and/or modify 9 ;; it under the terms of the GNU General Public License as published by 10 ;; the Free Software Foundation, either version 3 of the License, or 11 ;; (at your option) any later version. 12 13 ;; This program is distributed in the hope that it will be useful, 14 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of 15 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 ;; GNU General Public License for more details. 17 18 ;; You should have received a copy of the GNU General Public License 19 ;; along with this program. If not, see <http://www.gnu.org/licenses/>. 20 21 ;;; Commentary: 22 23 ;; This file contains the core functionality of multiple-cursors. 24 ;; Please see multiple-cursors.el for more commentary. 25 26 ;;; Code: 27 28 (require 'cl-lib) 29 (require 'rect) 30 31 (defvar mc--read-char) 32 33 (defface mc/cursor-face 34 '((t (:inverse-video t))) 35 "The face used for fake cursors" 36 :group 'multiple-cursors) 37 38 (defface mc/region-face 39 '((t :inherit region)) 40 "The face used for fake regions" 41 :group 'multiple-cursors) 42 43 (defmacro mc/add-fake-cursor-to-undo-list (&rest forms) 44 "Make sure point is in the right place when undoing" 45 (let ((uc (make-symbol "undo-cleaner"))) 46 `(let ((,uc (cons 'apply (cons 'deactivate-cursor-after-undo (list id))))) 47 (setq buffer-undo-list (cons ,uc buffer-undo-list)) 48 ,@forms 49 (if (eq ,uc (car buffer-undo-list)) ;; if nothing has been added to the undo-list 50 (setq buffer-undo-list (cdr buffer-undo-list)) ;; then pop the cleaner right off again 51 (setq buffer-undo-list ;; otherwise add a function to activate this cursor 52 (cons (cons 'apply (cons 'activate-cursor-for-undo (list id))) buffer-undo-list)))))) 53 54 (defun mc/all-fake-cursors (&optional start end) 55 (cl-remove-if-not 'mc/fake-cursor-p 56 (overlays-in (or start (point-min)) 57 (or end (point-max))))) 58 59 (defmacro mc/for-each-fake-cursor (&rest forms) 60 "Runs the body for each fake cursor, bound to the name cursor" 61 `(mapc #'(lambda (cursor) ,@forms) 62 (mc/all-fake-cursors))) 63 64 (defmacro mc/save-excursion (&rest forms) 65 "Saves and restores all the state that multiple-cursors cares about." 66 (let ((cs (make-symbol "current-state"))) 67 `(let ((,cs (mc/store-current-state-in-overlay 68 (make-overlay (point) (point) nil nil t)))) 69 (overlay-put ,cs 'type 'original-cursor) 70 (save-excursion ,@forms) 71 (mc/pop-state-from-overlay ,cs)))) 72 73 (defun mc--compare-by-overlay-start (o1 o2) 74 (< (overlay-start o1) (overlay-start o2))) 75 76 (defmacro mc/for-each-cursor-ordered (&rest forms) 77 "Runs the body for each cursor, fake and real, bound to the name cursor" 78 (let ((rci (make-symbol "real-cursor-id"))) 79 `(let ((,rci (overlay-get (mc/create-fake-cursor-at-point) 'mc-id))) 80 (mapc #'(lambda (cursor) 81 (when (mc/fake-cursor-p cursor) 82 ,@forms)) 83 (sort (overlays-in (point-min) (point-max)) 'mc--compare-by-overlay-start)) 84 (mc/pop-state-from-overlay (mc/cursor-with-id ,rci))))) 85 86 (defmacro mc/save-window-scroll (&rest forms) 87 "Saves and restores the window scroll position" 88 (let ((p (make-symbol "p")) 89 (s (make-symbol "start")) 90 (h (make-symbol "hscroll"))) 91 `(let ((,p (set-marker (make-marker) (point))) 92 (,s (set-marker (make-marker) (window-start))) 93 (,h (window-hscroll))) 94 ,@forms 95 (goto-char ,p) 96 (set-window-start nil ,s t) 97 (set-window-hscroll nil ,h) 98 (set-marker ,p nil) 99 (set-marker ,s nil)))) 100 101 (defun mc/make-cursor-overlay-at-eol (pos) 102 "Create overlay to look like cursor at end of line." 103 (let ((overlay (make-overlay pos pos nil nil nil))) 104 (overlay-put overlay 'after-string (propertize " " 'face 'mc/cursor-face)) 105 overlay)) 106 107 (defun mc/make-cursor-overlay-inline (pos) 108 "Create overlay to look like cursor inside text." 109 (let ((overlay (make-overlay pos (1+ pos) nil nil nil))) 110 (overlay-put overlay 'face 'mc/cursor-face) 111 overlay)) 112 113 (defun mc/make-cursor-overlay-at-point () 114 "Create overlay to look like cursor. 115 Special case for end of line, because overlay over a newline 116 highlights the entire width of the window." 117 (if (eolp) 118 (mc/make-cursor-overlay-at-eol (point)) 119 (mc/make-cursor-overlay-inline (point)))) 120 121 (defun mc/make-region-overlay-between-point-and-mark () 122 "Create overlay to look like active region." 123 (let ((overlay (make-overlay (mark) (point) nil nil t))) 124 (overlay-put overlay 'face 'mc/region-face) 125 (overlay-put overlay 'type 'additional-region) 126 overlay)) 127 128 (defvar mc/cursor-specific-vars '(transient-mark-mode 129 kill-ring 130 kill-ring-yank-pointer 131 mark-ring 132 mark-active 133 yank-undo-function 134 autopair-action 135 autopair-wrap-action 136 er/history) 137 "A list of vars that need to be tracked on a per-cursor basis.") 138 139 (defun mc/store-current-state-in-overlay (o) 140 "Store relevant info about point and mark in the given overlay." 141 (overlay-put o 'point (set-marker (make-marker) (point))) 142 (overlay-put o 'mark (set-marker (make-marker) (mark))) 143 (dolist (var mc/cursor-specific-vars) 144 (when (boundp var) (overlay-put o var (symbol-value var)))) 145 o) 146 147 (defun mc/restore-state-from-overlay (o) 148 "Restore point and mark from stored info in the given overlay." 149 (goto-char (overlay-get o 'point)) 150 (set-marker (mark-marker) (overlay-get o 'mark)) 151 (dolist (var mc/cursor-specific-vars) 152 (when (boundp var) (set var (overlay-get o var))))) 153 154 (defun mc/remove-fake-cursor (o) 155 "Delete overlay with state, including dependent overlays and markers." 156 (set-marker (overlay-get o 'point) nil) 157 (set-marker (overlay-get o 'mark) nil) 158 (mc/delete-region-overlay o) 159 (delete-overlay o)) 160 161 (defun mc/pop-state-from-overlay (o) 162 "Restore the state stored in given overlay and then remove the overlay." 163 (mc/restore-state-from-overlay o) 164 (mc/remove-fake-cursor o)) 165 166 (defun mc/delete-region-overlay (o) 167 "Remove the dependent region overlay for a given cursor overlay." 168 (ignore-errors 169 (delete-overlay (overlay-get o 'region-overlay)))) 170 171 (defvar mc--current-cursor-id 0 172 "Var to store increasing id of fake cursors, used to keep track of them for undo.") 173 174 (defun mc/create-cursor-id () 175 "Returns a unique cursor id" 176 (cl-incf mc--current-cursor-id)) 177 178 (defvar mc--max-cursors-original nil 179 "This variable maintains the original maximum number of cursors. 180 When `mc/create-fake-cursor-at-point' is called and 181 `mc/max-cursors' is overridden, this value serves as a backup so 182 that `mc/max-cursors' can take on a new value. When 183 `mc/remove-fake-cursors' is called, the values are reset.") 184 185 (defcustom mc/max-cursors nil 186 "Safety ceiling for the number of active cursors. 187 If your emacs slows down or freezes when using too many cursors, 188 customize this value appropriately. 189 190 Cursors will be added until this value is reached, at which point 191 you can either temporarily override the value or abort the 192 operation entirely. 193 194 If this value is nil, there is no ceiling." 195 :type '(integer) 196 :group 'multiple-cursors) 197 198 (defun mc/create-fake-cursor-at-point (&optional id) 199 "Add a fake cursor and possibly a fake active region overlay based on point and mark. 200 Saves the current state in the overlay to be restored later." 201 (unless mc--max-cursors-original 202 (setq mc--max-cursors-original mc/max-cursors)) 203 (when mc/max-cursors 204 (unless (< (mc/num-cursors) mc/max-cursors) 205 (if (yes-or-no-p (format "%d active cursors. Continue? " (mc/num-cursors))) 206 (setq mc/max-cursors (read-number "Enter a new, temporary maximum: ")) 207 (mc/remove-fake-cursors) 208 (error "Aborted: too many cursors")))) 209 (let ((overlay (mc/make-cursor-overlay-at-point))) 210 (overlay-put overlay 'mc-id (or id (mc/create-cursor-id))) 211 (overlay-put overlay 'type 'fake-cursor) 212 (overlay-put overlay 'priority 100) 213 (mc/store-current-state-in-overlay overlay) 214 (when (use-region-p) 215 (overlay-put overlay 'region-overlay 216 (mc/make-region-overlay-between-point-and-mark))) 217 overlay)) 218 219 (defun mc/execute-command (cmd) 220 "Run command, simulating the parts of the command loop that makes sense for fake cursors." 221 (setq this-command cmd) 222 (run-hooks 'pre-command-hook) 223 (unless (eq this-command 'ignore) 224 (call-interactively cmd)) 225 (run-hooks 'post-command-hook) 226 (when deactivate-mark (deactivate-mark))) 227 228 (defvar mc--executing-command-for-fake-cursor nil) 229 230 (defun mc/execute-command-for-fake-cursor (cmd cursor) 231 (let ((mc--executing-command-for-fake-cursor t) 232 (id (overlay-get cursor 'mc-id)) 233 (annoying-arrows-mode nil) 234 (smooth-scroll-margin 0)) 235 (mc/add-fake-cursor-to-undo-list 236 (mc/pop-state-from-overlay cursor) 237 (ignore-errors 238 (mc/execute-command cmd) 239 (mc/create-fake-cursor-at-point id))))) 240 241 (defun mc/execute-command-for-all-fake-cursors (cmd) 242 "Calls CMD interactively for each cursor. 243 It works by moving point to the fake cursor, setting 244 up the proper environment, and then removing the cursor. 245 After executing the command, it sets up a new fake 246 cursor with updated info." 247 (mc/save-excursion 248 (mc/save-window-scroll 249 (mc/for-each-fake-cursor 250 (save-excursion 251 (mc/execute-command-for-fake-cursor cmd cursor))))) 252 (mc--reset-read-prompts)) 253 254 (defun mc/execute-command-for-all-cursors (cmd) 255 "Calls CMD interactively for the real cursor and all fakes." 256 (call-interactively cmd) 257 (mc/execute-command-for-all-fake-cursors cmd)) 258 259 ;; Intercept some reading commands so you won't have to 260 ;; answer them for every single cursor 261 262 (defvar mc--read-char nil) 263 (defvar multiple-cursors-mode nil) 264 (defadvice read-char (around mc-support activate) 265 (if (not multiple-cursors-mode) 266 ad-do-it 267 (unless mc--read-char 268 (setq mc--read-char ad-do-it)) 269 (setq ad-return-value mc--read-char))) 270 271 (defvar mc--read-quoted-char nil) 272 (defadvice read-quoted-char (around mc-support activate) 273 (if (not multiple-cursors-mode) 274 ad-do-it 275 (unless mc--read-quoted-char 276 (setq mc--read-quoted-char ad-do-it)) 277 (setq ad-return-value mc--read-quoted-char))) 278 279 (defun mc--reset-read-prompts () 280 (setq mc--read-char nil) 281 (setq mc--read-quoted-char nil)) 282 283 (mc--reset-read-prompts) 284 285 (defun mc/fake-cursor-p (o) 286 "Predicate to check if an overlay is a fake cursor" 287 (eq (overlay-get o 'type) 'fake-cursor)) 288 289 (defun mc/cursor-with-id (id) 290 "Find the first cursor with the given id, or nil" 291 (cl-find-if #'(lambda (o) (and (mc/fake-cursor-p o) 292 (= id (overlay-get o 'mc-id)))) 293 (overlays-in (point-min) (point-max)))) 294 295 (defvar mc--stored-state-for-undo nil 296 "Variable to keep the state of the real cursor while undoing a fake one") 297 298 (defun activate-cursor-for-undo (id) 299 "Called when undoing to temporarily activate the fake cursor which action is being undone." 300 (let ((cursor (mc/cursor-with-id id))) 301 (when cursor 302 (setq mc--stored-state-for-undo (mc/store-current-state-in-overlay 303 (make-overlay (point) (point) nil nil t))) 304 (mc/pop-state-from-overlay cursor)))) 305 306 (defun deactivate-cursor-after-undo (id) 307 "Called when undoing to reinstate the real cursor after undoing a fake one." 308 (when mc--stored-state-for-undo 309 (mc/create-fake-cursor-at-point id) 310 (mc/pop-state-from-overlay mc--stored-state-for-undo) 311 (setq mc--stored-state-for-undo nil))) 312 313 (defun mc/prompt-for-inclusion-in-whitelist (original-command) 314 "Asks the user, then adds the command either to the once-list or the all-list." 315 (let ((all-p (y-or-n-p (format "Do %S for all cursors?" original-command)))) 316 (if all-p 317 (add-to-list 'mc/cmds-to-run-for-all original-command) 318 (add-to-list 'mc/cmds-to-run-once original-command)) 319 (mc/save-lists) 320 all-p)) 321 322 (defun mc/num-cursors () 323 "The number of cursors (real and fake) in the buffer." 324 (1+ (cl-count-if 'mc/fake-cursor-p 325 (overlays-in (point-min) (point-max))))) 326 327 (defvar mc--this-command nil 328 "Used to store the original command being run.") 329 (make-variable-buffer-local 'mc--this-command) 330 331 (defun mc/make-a-note-of-the-command-being-run () 332 "Used with pre-command-hook to store the original command being run. 333 Since that cannot be reliably determined in the post-command-hook. 334 335 Specifically, this-original-command isn't always right, because it could have 336 been remapped. And certain modes (cua comes to mind) will change their 337 remapping based on state. So a command that changes the state will afterwards 338 not be recognized through the command-remapping lookup." 339 (unless mc--executing-command-for-fake-cursor 340 (let ((cmd (or (command-remapping this-original-command) 341 this-original-command))) 342 (setq mc--this-command (and (not (eq cmd 'god-mode-self-insert)) 343 cmd))))) 344 345 (defun mc/execute-this-command-for-all-cursors () 346 "Wrap around `mc/execute-this-command-for-all-cursors-1' to protect hook." 347 (condition-case error 348 (mc/execute-this-command-for-all-cursors-1) 349 (error 350 (message "[mc] problem in `mc/execute-this-command-for-all-cursors': %s" 351 (error-message-string error))))) 352 353 ;; execute-kbd-macro should never be run for fake cursors. The real cursor will 354 ;; execute the keyboard macro, resulting in new commands in the command loop, 355 ;; and the fake cursors can pick up on those instead. 356 (defadvice execute-kbd-macro (around skip-fake-cursors activate) 357 (unless mc--executing-command-for-fake-cursor 358 ad-do-it)) 359 360 (defun mc/execute-this-command-for-all-cursors-1 () 361 "Used with post-command-hook to execute supported commands for all cursors. 362 363 It uses two lists of commands to know what to do: the run-once 364 list and the run-for-all list. If a command is in neither of these lists, 365 it will prompt for the proper action and then save that preference. 366 367 Some commands are so unsupported that they are even prevented for 368 the original cursor, to inform about the lack of support." 369 (unless mc--executing-command-for-fake-cursor 370 371 (if (eq 1 (mc/num-cursors)) ;; no fake cursors? disable mc-mode 372 (multiple-cursors-mode 0) 373 (when this-original-command 374 (let ((original-command (or mc--this-command 375 (command-remapping this-original-command) 376 this-original-command))) 377 378 ;; skip keyboard macros, since they will generate actual commands that are 379 ;; also run in the command loop - we'll handle those later instead. 380 (when (functionp original-command) 381 382 ;; if it's a lambda, we can't know if it's supported or not 383 ;; - so go ahead and assume it's ok, because we're just optimistic like that 384 (if (or (not (symbolp original-command)) 385 ;; lambda registered by smartrep 386 (string-prefix-p "(" (symbol-name original-command))) 387 (mc/execute-command-for-all-fake-cursors original-command) 388 389 ;; smartrep `intern's commands into own obarray to help 390 ;; `describe-bindings'. So, let's re-`intern' here to 391 ;; make the command comparable by `eq'. 392 (setq original-command (intern (symbol-name original-command))) 393 394 ;; otherwise it's a symbol, and we can be more thorough 395 (if (get original-command 'mc--unsupported) 396 (message "%S is not supported with multiple cursors%s" 397 original-command 398 (get original-command 'mc--unsupported)) 399 (when (and original-command 400 (not (memq original-command mc--default-cmds-to-run-once)) 401 (not (memq original-command mc/cmds-to-run-once)) 402 (or (memq original-command mc--default-cmds-to-run-for-all) 403 (memq original-command mc/cmds-to-run-for-all) 404 (mc/prompt-for-inclusion-in-whitelist original-command))) 405 (mc/execute-command-for-all-fake-cursors original-command)))))))))) 406 407 (defun mc/remove-fake-cursors () 408 "Remove all fake cursors. 409 Do not use to conclude editing with multiple cursors. For that 410 you should disable multiple-cursors-mode." 411 (mc/for-each-fake-cursor 412 (mc/remove-fake-cursor cursor)) 413 (when mc--max-cursors-original 414 (setq mc/max-cursors mc--max-cursors-original)) 415 (setq mc--max-cursors-original nil)) 416 417 (defun mc/keyboard-quit () 418 "Deactivate mark if there are any active, otherwise exit multiple-cursors-mode." 419 (interactive) 420 (if (not (use-region-p)) 421 (multiple-cursors-mode 0) 422 (deactivate-mark))) 423 424 (defvar mc/keymap nil 425 "Keymap while multiple cursors are active. 426 Main goal of the keymap is to rebind C-g and <return> to conclude 427 multiple cursors editing.") 428 (unless mc/keymap 429 (setq mc/keymap (make-sparse-keymap)) 430 (define-key mc/keymap (kbd "C-g") 'mc/keyboard-quit) 431 (define-key mc/keymap (kbd "<return>") 'multiple-cursors-mode) 432 (when (fboundp 'phi-search) 433 (define-key mc/keymap (kbd "C-s") 'phi-search)) 434 (when (fboundp 'phi-search-backward) 435 (define-key mc/keymap (kbd "C-r") 'phi-search-backward))) 436 437 (defun mc--all-equal (list) 438 "Are all the items in LIST equal?" 439 (let ((first (car list)) 440 (all-equal t)) 441 (while (and all-equal list) 442 (setq all-equal (equal first (car list))) 443 (setq list (cdr list))) 444 all-equal)) 445 446 (defun mc--kill-ring-entries () 447 "Return the latest kill-ring entry for each cursor. 448 The entries are returned in the order they are found in the buffer." 449 (let (entries) 450 (mc/for-each-cursor-ordered 451 (setq entries (cons (car (overlay-get cursor 'kill-ring)) entries))) 452 (reverse entries))) 453 454 (defun mc--maybe-set-killed-rectangle () 455 "Add the latest kill-ring entry for each cursor to killed-rectangle. 456 So you can paste it in later with `yank-rectangle'." 457 (let ((entries (let (mc/max-cursors) (mc--kill-ring-entries)))) 458 (unless (mc--all-equal entries) 459 (setq killed-rectangle entries)))) 460 461 (defvar mc/unsupported-minor-modes '(company-mode auto-complete-mode flyspell-mode jedi-mode) 462 "List of minor-modes that does not play well with multiple-cursors. 463 They are temporarily disabled when multiple-cursors are active.") 464 465 (defvar mc/temporarily-disabled-minor-modes nil 466 "The list of temporarily disabled minor-modes.") 467 (make-variable-buffer-local 'mc/temporarily-disabled-minor-modes) 468 469 (defun mc/temporarily-disable-minor-mode (mode) 470 "If MODE is available and turned on, remember that and turn it off." 471 (when (and (boundp mode) (eval mode)) 472 (add-to-list 'mc/temporarily-disabled-minor-modes mode) 473 (funcall mode -1))) 474 475 (defun mc/temporarily-disable-unsupported-minor-modes () 476 (mapc 'mc/temporarily-disable-minor-mode mc/unsupported-minor-modes)) 477 478 (defun mc/enable-minor-mode (mode) 479 (funcall mode 1)) 480 481 (defun mc/enable-temporarily-disabled-minor-modes () 482 (mapc 'mc/enable-minor-mode mc/temporarily-disabled-minor-modes) 483 (setq mc/temporarily-disabled-minor-modes nil)) 484 485 (defcustom mc/mode-line 486 `(" mc:" (:eval (format ,(propertize "%d" 'face 'font-lock-warning-face) 487 (mc/num-cursors)))) 488 "What to display in the mode line while multiple-cursors-mode is active." 489 :group 'multiple-cursors) 490 (put 'mc/mode-line 'risky-local-variable t) 491 492 ;;;###autoload 493 (define-minor-mode multiple-cursors-mode 494 "Mode while multiple cursors are active." 495 nil mc/mode-line mc/keymap 496 (if multiple-cursors-mode 497 (progn 498 (mc/temporarily-disable-unsupported-minor-modes) 499 (add-hook 'pre-command-hook 'mc/make-a-note-of-the-command-being-run nil t) 500 (add-hook 'post-command-hook 'mc/execute-this-command-for-all-cursors t t) 501 (run-hooks 'multiple-cursors-mode-enabled-hook)) 502 (remove-hook 'post-command-hook 'mc/execute-this-command-for-all-cursors t) 503 (remove-hook 'pre-command-hook 'mc/make-a-note-of-the-command-being-run t) 504 (setq mc--this-command nil) 505 (mc--maybe-set-killed-rectangle) 506 (mc/remove-fake-cursors) 507 (mc/enable-temporarily-disabled-minor-modes) 508 (run-hooks 'multiple-cursors-mode-disabled-hook))) 509 510 (add-hook 'after-revert-hook #'(lambda () (multiple-cursors-mode 0))) 511 512 (defun mc/maybe-multiple-cursors-mode () 513 "Enable multiple-cursors-mode if there is more than one currently active cursor." 514 (if (> (mc/num-cursors) 1) 515 (multiple-cursors-mode 1) 516 (multiple-cursors-mode 0))) 517 518 (defmacro unsupported-cmd (cmd msg) 519 "Adds command to list of unsupported commands and prevents it 520 from being executed if in multiple-cursors-mode." 521 `(progn 522 (put (quote ,cmd) 'mc--unsupported ,msg) 523 (defadvice ,cmd (around unsupported-advice activate) 524 "command isn't supported with multiple cursors" 525 (unless (and multiple-cursors-mode (called-interactively-p 'any)) 526 ad-do-it)))) 527 528 ;; Commands that does not work with multiple-cursors 529 (unsupported-cmd isearch-forward ". Feel free to add a compatible version.") 530 (unsupported-cmd isearch-backward ". Feel free to add a compatible version.") 531 532 ;; Make sure pastes from other programs are added to all kill-rings when yanking 533 (defadvice current-kill (before interprogram-paste-for-all-cursors activate) 534 (let ((interprogram-paste (and (= n 0) 535 interprogram-paste-function 536 (funcall interprogram-paste-function)))) 537 (when interprogram-paste 538 ;; Add interprogram-paste to normal kill ring, just 539 ;; like current-kill usually does for itself. 540 ;; We have to do the work for it tho, since the funcall only returns 541 ;; something once. It is not a pure function. 542 (let ((interprogram-cut-function nil)) 543 (if (listp interprogram-paste) 544 (mapc 'kill-new (nreverse interprogram-paste)) 545 (kill-new interprogram-paste)) 546 ;; And then add interprogram-paste to the kill-rings 547 ;; of all the other cursors too. 548 (mc/for-each-fake-cursor 549 (let ((kill-ring (overlay-get cursor 'kill-ring)) 550 (kill-ring-yank-pointer (overlay-get cursor 'kill-ring-yank-pointer))) 551 (if (listp interprogram-paste) 552 (mapc 'kill-new (nreverse interprogram-paste)) 553 (kill-new interprogram-paste)) 554 (overlay-put cursor 'kill-ring kill-ring) 555 (overlay-put cursor 'kill-ring-yank-pointer kill-ring-yank-pointer))))))) 556 557 (defvar mc/list-file (locate-user-emacs-file ".mc-lists.el") 558 "The position of the file that keeps track of your preferences 559 for running commands with multiple cursors.") 560 561 (defun mc/dump-list (list-symbol) 562 "Insert (setq 'LIST-SYMBOL LIST-VALUE) to current buffer." 563 (cl-symbol-macrolet ((value (symbol-value list-symbol))) 564 (insert "(setq " (symbol-name list-symbol) "\n" 565 " '(") 566 (newline-and-indent) 567 (set list-symbol 568 (sort value (lambda (x y) (string-lessp (symbol-name x) 569 (symbol-name y))))) 570 (mapc #'(lambda (cmd) (insert (format "%S" cmd)) (newline-and-indent)) 571 value) 572 (insert "))") 573 (newline))) 574 575 (defun mc/save-lists () 576 "Saves preferences for running commands with multiple cursors to `mc/list-file'" 577 (with-temp-file mc/list-file 578 (emacs-lisp-mode) 579 (insert ";; This file is automatically generated by the multiple-cursors extension.") 580 (newline) 581 (insert ";; It keeps track of your preferences for running commands with multiple cursors.") 582 (newline) 583 (newline) 584 (mc/dump-list 'mc/cmds-to-run-for-all) 585 (newline) 586 (mc/dump-list 'mc/cmds-to-run-once))) 587 588 (defvar mc/cmds-to-run-once nil 589 "Commands to run only once in multiple-cursors-mode.") 590 591 (defvar mc--default-cmds-to-run-once nil 592 "Default set of commands to run only once in multiple-cursors-mode.") 593 594 (setq mc--default-cmds-to-run-once '(mc/edit-lines 595 mc/edit-ends-of-lines 596 mc/edit-beginnings-of-lines 597 mc/mark-next-like-this 598 mc/mark-next-like-this-word 599 mc/mark-next-like-this-symbol 600 mc/mark-next-word-like-this 601 mc/mark-next-symbol-like-this 602 mc/mark-previous-like-this 603 mc/mark-previous-word-like-this 604 mc/mark-previous-symbol-like-this 605 mc/mark-all-like-this 606 mc/mark-all-words-like-this 607 mc/mark-all-symbols-like-this 608 mc/mark-more-like-this-extended 609 mc/mark-all-like-this-in-defun 610 mc/mark-all-words-like-this-in-defun 611 mc/mark-all-symbols-like-this-in-defun 612 mc/mark-all-like-this-dwim 613 mc/mark-all-dwim 614 mc/mark-sgml-tag-pair 615 mc/insert-numbers 616 mc/insert-letters 617 mc/sort-regions 618 mc/reverse-regions 619 mc/cycle-forward 620 mc/cycle-backward 621 mc/add-cursor-on-click 622 mc/mark-pop 623 mc/add-cursors-to-all-matches 624 mc/mmlte--left 625 mc/mmlte--right 626 mc/mmlte--up 627 mc/mmlte--down 628 mc/unmark-next-like-this 629 mc/unmark-previous-like-this 630 mc/skip-to-next-like-this 631 mc/skip-to-previous-like-this 632 rrm/switch-to-multiple-cursors 633 mc-hide-unmatched-lines-mode 634 hum/keyboard-quit 635 hum/unhide-invisible-overlays 636 save-buffer 637 ido-exit-minibuffer 638 exit-minibuffer 639 minibuffer-complete-and-exit 640 execute-extended-command 641 undo 642 redo 643 undo-tree-undo 644 undo-tree-redo 645 universal-argument 646 universal-argument-more 647 universal-argument-other-key 648 negative-argument 649 digit-argument 650 top-level 651 recenter-top-bottom 652 describe-mode 653 describe-key-1 654 describe-function 655 describe-bindings 656 describe-prefix-bindings 657 view-echo-area-messages 658 other-window 659 kill-buffer-and-window 660 split-window-right 661 split-window-below 662 delete-other-windows 663 toggle-window-split 664 mwheel-scroll 665 scroll-up-command 666 scroll-down-command 667 mouse-set-point 668 mouse-drag-region 669 quit-window 670 toggle-read-only 671 windmove-left 672 windmove-right 673 windmove-up 674 windmove-down)) 675 676 (defvar mc--default-cmds-to-run-for-all nil 677 "Default set of commands that should be mirrored by all cursors") 678 679 (setq mc--default-cmds-to-run-for-all '(mc/keyboard-quit 680 self-insert-command 681 quoted-insert 682 previous-line 683 next-line 684 newline 685 newline-and-indent 686 open-line 687 delete-blank-lines 688 transpose-chars 689 transpose-lines 690 transpose-paragraphs 691 transpose-regions 692 join-line 693 right-char 694 right-word 695 forward-char 696 forward-word 697 left-char 698 left-word 699 backward-char 700 backward-word 701 forward-paragraph 702 backward-paragraph 703 upcase-word 704 downcase-word 705 capitalize-word 706 forward-list 707 backward-list 708 hippie-expand 709 hippie-expand-lines 710 yank 711 yank-pop 712 append-next-kill 713 kill-word 714 kill-line 715 kill-whole-line 716 backward-kill-word 717 backward-delete-char-untabify 718 delete-char delete-forward-char 719 delete-backward-char 720 py-electric-backspace 721 c-electric-backspace 722 org-delete-backward-char 723 cperl-electric-backspace 724 python-indent-dedent-line-backspace 725 paredit-backward-delete 726 autopair-backspace 727 just-one-space 728 zap-to-char 729 end-of-line 730 set-mark-command 731 exchange-point-and-mark 732 cua-set-mark 733 cua-replace-region 734 cua-delete-region 735 move-end-of-line 736 beginning-of-line 737 move-beginning-of-line 738 kill-ring-save 739 back-to-indentation 740 subword-forward 741 subword-backward 742 subword-mark 743 subword-kill 744 subword-backward-kill 745 subword-transpose 746 subword-capitalize 747 subword-upcase 748 subword-downcase 749 er/expand-region 750 er/contract-region 751 smart-forward 752 smart-backward 753 smart-up 754 smart-down)) 755 756 (defvar mc/cmds-to-run-for-all nil 757 "Commands to run for all cursors in multiple-cursors-mode") 758 759 (load mc/list-file t) ;; load, but no errors if it does not exist yet please 760 761 (provide 'multiple-cursors-core) 762 763 ;; Local Variables: 764 ;; coding: utf-8 765 ;; End: 766 767 ;;; multiple-cursors-core.el ends here